Hibernate/JPA - Entity listener not being called properly

后端 未结 3 572
悲哀的现实
悲哀的现实 2021-01-02 19:52

I\'m trying to leverage EntityListener objects and callback methods within my Seam/Hibernate/JPA application. I\'m using a Seam 2.2-managed persistence context on JBoss 5.1

3条回答
  •  囚心锁ツ
    2021-01-02 20:45

    Without the actual tests you've ran, the way you've ran them and the output you've got (from your listener) it is hard to say anything clever, however using MySQL with the following table and data

    CREATE TABLE `test` (
      `id` int(11)
      `data` char(1),
      PRIMARY KEY (`id`)
    );
    
    +----+------+
    | id | data |
    +----+------+
    |  1 | a    |
    +----+------+
    

    I've ran this test

    EntityManagerFactory emf = ...
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();
    
    // persisting new item
    Test b = new Test();
    b.id = 2;
    b.data = 'b';
    
    tx.begin();
    em.persist(b);
    tx.commit();
    
    // update existing item
    b.data = 'a';
    
    tx.begin();
    em.merge(b);
    tx.commit();
    
    // load existing
    Test a = em.find(Test.class, 1);
    
    // remove existing
    tx.begin();
    em.remove(b);
    tx.commit();
    
    em.close();
    emf.close();
    

    and got the following output

    prePersist(2: b)
    postPersist(2: b)
    preUpdate(2: a)
    postUpdate(2: a)
    postLoad(1: a)
    preRemove(2: a)
    postRemove(2: a)
    

    (I've implemented toString() in Test so it emits id + ": " + data and I've reduced the logging statements in my listener class to System.out.format("preXxx(%s)\n", e) so that it would be read better.)

    Please see if this works for you in your environment for starters, so that we could narrow down the problem, but at least post some of your input/output.


    I've tried to boot up a simple JBoss/Seam test application for myself to run a test, however I don't get Seam … at all. Anyway, I took a look at your examples and here's what I think your problem is.

    Test 1 / Ouput 1

    I assume that your runTest() method starts a managed persistence session or something like that, so before the method gets called entityManager.getTransaction().begin() is called by Seam, and when the method exists entityManager.getTransaction().commit() is called. Here's my opinion on what seems to happen in your scenario.

    // transaction begin
    // persist - @PrePersist called
    this.entityManager.persist(e);
    // flush - @PostPersist should be called
    this.entityManager.flush();
    // clear - the context is cleared
    this.entityManager.clear();
    // transaction end
    

    I've tested this scenario, however using MySQL with manual persistence management @PostPersist is called.

    I've tried setting entityManager.setFlushMode(...) to FlushModeType.AUTO and FlushModeType.COMMIT but it changes nothing. However in the Seam documentation there is a third enum, FlushModeType.MANUAL, which isn't in the JPA specification and is Seam specific. It should be fed to the @Begin annotation (this annotation probably indicates that the annotated method starts the transaction at hand).

    I'm quite certain that in your case flush() commits nothing to the database until the transaction is over (the methods runs out). If you remove the call to the clear() method @PostPersist should be called.

    Test 2 / Output 2

    This seems just fine to me!

    Test 3 / Output 3

    I assume your problem is that @PrePersist and @PostPersist doesn't get called at all, but you call persist(). Because you use find() the returned instances will already be managed. Calling persist() on them does nothing. However mutating their state and calling flush() triggers @PreUpdate. @PostUpdate doesn't get called of the exact same reason @PostPersist didn't get called in the first test: you clear the persistence context before anything could propagate to the database.

    Conclusion

    Your problem comes down to the fact that you clear() your persistence context before anything gets committed to the database.

    I suggest you to make some really simple tests and try playing with the FlushModeType settings I mentioned. Update your Hibernate version. I use the latest version from 3.x.x series (3.8.6.Final). By the way, you didn't exactly share your Hibernate version with us, but it could matter a lot!

提交回复
热议问题