Hibernate/JPA - Entity listener not being called properly

后端 未结 3 578
悲哀的现实
悲哀的现实 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:39

    This is not the normal behavior. I work on a project that use seam 2.2.2 with seam managed persistence context, jpa/hibernate, jboss 5.1 and mysql and all the callbacks are correctly invoked. Maybe there is a bug on your test case.

    0 讨论(0)
  • 2021-01-02 20:40

    Sorry if i give a wrong answer... i don't know Seam.

    But in your subject you say "Hibernate/JPA" which is unclear. Do you persist entities using a Session from a SessionFactory, or an EntityManager from an EntityManagerFactory?

    There is a big difference because if you use Seam with a SessionFactory, the big difference is that by default the JPA listeners (which fire your annotated callbacks) are not registred by default, while they are with an EntityManagerFactory. So it may be possible that you are using a SessionFactory, and that someone else on your project, who configured that session factory, only registered a subset of all the JPA callback listeners.

    See: http://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/configuration.html#d0e865


    Edit: Ok sorry, you use an EntityManager...

    but perhaps it would be a good idea to try to get that SessionFactory behind the EntityManagerFactory, and see which event listeners are registred. Are you alone on that application? If someone tried to register a custom/legacy eventlistener or something, he may have overriden a JPA eventlistener.

    This can be achieved by something like that:

    EntityManager em = ...
    Session session = (Session)em.getDelegage()
    SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl)session.getSessionFactory();
    EventListeners el = sessionFactoryImpl.getEventListeners()
    

    And then you can look what's inside, for exemple, according to your problem, you can compare:

    el.getPreLoadEventListeners()
    el.getPreDeleteEventListeners()
    

    And remember the "default behaviour" is: http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html_single/#d0e865

    It seems that it is possible to easily override JPA default listeners, see that: http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/listeners.html

    It would be nice if you show us your persistence.xml

    0 讨论(0)
  • 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!

    0 讨论(0)
提交回复
热议问题