Hibernate / JPA - 实体侦听器未正确调用 [英] Hibernate/JPA - Entity listener not being called properly

查看:191
本文介绍了Hibernate / JPA - 实体侦听器未正确调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我的Seam / Hibernate / JPA应用程序中利用EntityListener对象和回调方法。我在JBoss 5.1上使用Seam 2.2管理的持久化上下文,在后端使用PostgreSQL 9.1。我有以下实体声明:

  @Entity(name =TestEntity)
@EntityListeners(TestCallback.class )
@Table(name =tbl_test)
public class TestEntity implements Serializable {

private static final long serialVersionUID = 2016897066783042092L;

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator =xxx)
@SequenceGenerator(name =xxx,sequenceName =xxx)
@Index(name =xxx)
@DocumentId
private Long id = null;

@Column
private String test = null;
...
}

以及以下EntityListener回调类: / p>

  public class TestCallback {

/ **
*此类的记录器
* /
private Log logger = null;

public TestCallback(){
logger = Logging.getLog(TestCallback.class);
}

@PrePersist
public void prePersist(TestEntity e){
logger.debug(prePersist(TestEntity) - start); // $ NON-NLS-1 $

logger.debug(prePersist(TestEntity) - end); // $ NON-NLS-1 $
}

@PostPersist
public void postPersist(TestEntity e){
logger.debug(postPersist(TestEntity)开始); // $ NON-NLS-1 $

logger.debug(postPersist(TestEntity) - end); // $ NON-NLS-1 $
}

@PostLoad
public void postLoad(TestEntity e){
logger.debug(postLoad(TestEntity)开始); // $ NON-NLS-1 $

logger.debug(postLoad(TestEntity) - end); // $ NON-NLS-1 $
}

@PreUpdate
public void preUpdate(TestEntity e){
logger.debug(preUpdate(TestEntity)开始); // $ NON-NLS-1 $

logger.debug(preUpdate(TestEntity) - end); // $ NON-NLS-1 $
}

@PostUpdate
public void postUpdate(TestEntity e){
logger.debug(postUpdate(TestEntity)开始); // $ NON-NLS-1 $

logger.debug(postUpdate(TestEntity) - end); // $ NON-NLS-1 $
}

@PreRemove
public void preRemove(TestEntity e){
logger.debug(preRemove(TestEntity)开始); // $ NON-NLS-1 $

logger.debug(preRemove(TestEntity) - end); // $ NON-NLS-1 $
}

@PostRemove
public void postRemove(TestEntity e){
logger.debug(postRemove(TestEntity)开始); // $ NON-NLS-1 $

logger.debug(postRemove(TestEntity) - end); // $ NON-NLS-1 $
}
}

运行我的测试,但是,我没有看到我的所有回调方法被调用,我所期望的。我已运行以下方案的测试:




  • 保留新项目




  • p>然而,我看到被调用的唯一回调是:




    • @PrePersist

    • @PreRemove

    • @PostLoad

    • @PreUpdate



    剩余的回调不会按预期执行。这是正常的行为吗?我只是误解了吗?这与Seam管理事务的方式有关吗?



    我非常感谢您能给予的任何帮助。



    EDIT:根据请求,这里是我正在调用的代码和我收到的输出:



    测试1:

      public void runTest(){
    logger.debug(runTest() - start); // $ NON-NLS-1 $

    TestEntity e = new TestEntity();
    e.setTest(XXX);

    this.entityManager.persist(e);
    this.entityManager.flush();
    this.entityManager.clear();

    logger.debug(runTest() - end); // $ NON-NLS-1 $
    }

    输出1:

      12:27:56,307 INFO [STDOUT] 29735 DEBUG myapp.test.web.actions.test.TestAction  -   -  runTest b $ b 12:27:56,312 INFO [STDOUT] 29740 DEBUG myapp.test.entities.TestCallback  -   -  prePersist(TestEntity) -  start 
    12:27:56,312 INFO [STDOUT] 29740 DEBUG myapp.test.entities。 TestCallback - - prePersist(TestEntity) - end
    12:27:56,347 INFO [STDOUT] 29775 DEBUG myapp.test.web.actions.test.TestAction - - runTest() - end

    测试2:

      runTest2(){
    logger.debug(runTest2() - start); // $ NON-NLS-1 $

    String sql =SELECT DISTINCT t FROM TestEntity t;
    Query q = this.entityManager.createQuery(sql);

    List< TestEntity> l = q.getResultList();
    for(int i = 0; i String x = l.get(i).getTest();
    logger.debug(runTest2() - String x =+ x); // $ NON-NLS-1 $
    }

    logger.debug(runTest2() - end); // $ NON-NLS-1 $
    }

    输出2:

      12:28:36,964 INFO [STDOUT] 70392 DEBUG myapp.test.web.actions.test.TestAction  -   -  runTest2 b $ b 12:28:36,982 INFO [STDOUT] 70410 DEBUG myapp.test.entities.TestCallback  -   -  postLoad(TestEntity) -  start 
    12:28:36,982 INFO [STDOUT] 70410 DEBUG myapp.test.entities。 TestCallback - - postLoad(TestEntity) - end
    12:28:36,982 INFO [STDOUT] 70410 DEBUG myapp.test.web.actions.test.TestAction - - runTest2() - String x = XXX
    12 :28:36,983 INFO [STDOUT] 70411 DEBUG myapp.test.web.actions.test.TestAction - - runTest2() - end

    测试3:

      public void runTest3(){
    logger.debug () - start); // $ NON-NLS-1 $

    String sql =SELECT DISTINCT t FROM TestEntity t;
    Query q = this.entityManager.createQuery(sql);

    List< TestEntity> l = q.getResultList();
    for(int i = 0; i< l.size(); i ++){
    l.get(i).setTest(YYY+ System.currentTimeMillis());
    this.entityManager.persist(l.get(i));
    }
    this.entityManager.flush();
    this.entityManager.clear();

    随机rand = new SecureRandom();

    q = this.entityManager.createQuery(sql);
    l = q.getResultList();
    for(int i = 0; i< l.size(); i ++){
    this.entityManager.remove(l.get(i));
    }

    this.entityManager.flush();
    this.entityManager.clear();

    logger.debug(runTest3() - end); // $ NON-NLS-1 $
    }

    输出3:

      12:30:00,404 INFO [STDOUT] 153832 DEBUG myapp.test.web.actions.test.TestAction  -   -  runTest3() -  start 
    12:30:00,407 INFO [STDOUT] 153835 DEBUG myapp.test.entities.TestCallback - - postLoad(TestEntity) - start
    12:30:00,407 INFO [STDOUT] 153835 DEBUG myapp.test.entities。 TestCallback - - postLoad(TestEntity) - end
    12:30:00,408 INFO [STDOUT] 153836 DEBUG myapp.test.entities.TestCallback - - preUpdate(TestEntity) - start
    12:30:00,408 INFO [ STDOUT] 153836 DEBUG myapp.test.entities.TestCallback - - preUpdate(TestEntity) - end
    12:30:00,410 INFO [STDOUT] 153838 DEBUG myapp.test.entities.TestCallback - - postLoad(TestEntity) - start
    12:30:00,411 INFO [STDOUT] 153839 DEBUG myapp.test.entities.TestCallback - - postLoad(TestEntity) - end
    12:30:00,414 INFO [STDOUT] 153842调试myapp.test.entities。 TestCallback - - preRemove(TestEntity) - start
    12:30:00,414 INFO [STDOUT] 153842 DEBUG myapp.test.entities.TestCallback - - preRemove(TestEntity) - end
    12:30:00,453 INFO [ STDOUT] 153881 DEBUG myapp.test.web.actions.test.TestAction - - runTest3() - end


    解决方案

    对不起,如果我给错了答案...我不认识Seam。



    Hibernate / JPA,这是不清楚的。
    你是使用SessionFactory中的Session还是EntityManagerFactory中的EntityManager持久化实体?



    有很大的区别,因为如果你使用Seam和SessionFactory ,最大的区别是默认情况下,JPA侦听器(触发您的注释回调)不会被默认注册,而它们与EntityManagerFactory。
    所以可能是你正在使用一个SessionFactory,并且你的项目中的其他人配置了会话工厂,只注册了所有JPA回调监听器的一个子集。



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






    编辑:
    对不起,你使用EntityManager ...



    但也许这是一个好主意,试图获得SessionFactory后面EntityManagerFactory,并查看注册了哪些事件侦听器。你独自在那个应用程序吗?



    这可以通过类似的方式实现:

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

    然后你可以看看里面有什么exemple,根据你的问题,你可以比较:

      el.getPreLoadEventListeners()
    el.getPreDeleteEventListeners b $ b

    并记住默认行为是:
    http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html_single/#d0e865



    似乎可以轻松地覆盖JPA默认侦听器,请参阅:
    http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/listeners.html



    这将是很好,如果你告诉我们你的persistence.xml


    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 with PostgreSQL 9.1 on the backend. I have the following entity declared:

    @Entity(name = "TestEntity")
    @EntityListeners(TestCallback.class)
    @Table(name = "tbl_test")
    public class TestEntity implements Serializable {
    
        private static final long serialVersionUID = 2016897066783042092L;
    
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "xxx")
        @SequenceGenerator(name = "xxx", sequenceName = "xxx")
        @Index(name = "xxx")
        @DocumentId
        private Long id = null;
    
        @Column
        private String test = null;
    ...
    }
    

    along with the following EntityListener callback class:

    public class TestCallback {
    
        /**
         * Logger for this class
         */
        private Log logger = null;
    
        public TestCallback() {
            logger = Logging.getLog(TestCallback.class);
        }
    
        @PrePersist
        public void prePersist(TestEntity e) {
            logger.debug("prePersist(TestEntity) - start"); //$NON-NLS-1$
    
            logger.debug("prePersist(TestEntity) - end"); //$NON-NLS-1$
        }
    
        @PostPersist
        public void postPersist(TestEntity e) {
            logger.debug("postPersist(TestEntity) - start"); //$NON-NLS-1$
    
            logger.debug("postPersist(TestEntity) - end"); //$NON-NLS-1$
        }
    
        @PostLoad
        public void postLoad(TestEntity e) {
            logger.debug("postLoad(TestEntity) - start"); //$NON-NLS-1$
    
            logger.debug("postLoad(TestEntity) - end"); //$NON-NLS-1$
        }
    
        @PreUpdate
        public void preUpdate(TestEntity e) {
            logger.debug("preUpdate(TestEntity) - start"); //$NON-NLS-1$
    
            logger.debug("preUpdate(TestEntity) - end"); //$NON-NLS-1$
        }
    
        @PostUpdate
        public void postUpdate(TestEntity e) {
            logger.debug("postUpdate(TestEntity) - start"); //$NON-NLS-1$
    
            logger.debug("postUpdate(TestEntity) - end"); //$NON-NLS-1$
        }
    
        @PreRemove
        public void preRemove(TestEntity e) {
            logger.debug("preRemove(TestEntity) - start"); //$NON-NLS-1$
    
            logger.debug("preRemove(TestEntity) - end"); //$NON-NLS-1$
        }
    
        @PostRemove
        public void postRemove(TestEntity e) {
            logger.debug("postRemove(TestEntity) - start"); //$NON-NLS-1$
    
            logger.debug("postRemove(TestEntity) - end"); //$NON-NLS-1$
        }
    }
    

    When I run my test, however, I do not see all of my callback methods being called as I would expect. I've run tests of the following scenarios:

    • Persisting a new item
    • Updating an existing item
    • Loading an item
    • Deleting an item

    However, the only callbacks I see being called are:

    • @PrePersist
    • @PreRemove
    • @PostLoad
    • @PreUpdate

    The remaining callbacks do not get executed as expected. Is this the normal behavior? Am I just misunderstanding it? Does this have something to do with the way Seam manages transactions? Or, am I just not doing something right?

    I'd appreciate any help you can give.

    EDIT: As requested, here is the exact code I'm calling and the output I receive:

    Test 1:

    public void runTest() {
        logger.debug("runTest() - start"); //$NON-NLS-1$
    
        TestEntity e = new TestEntity();
        e.setTest("XXX");
    
        this.entityManager.persist(e);
        this.entityManager.flush();
        this.entityManager.clear();
    
        logger.debug("runTest() - end"); //$NON-NLS-1$
    }
    

    Output 1:

    12:27:56,307 INFO  [STDOUT] 29735 DEBUG myapp.test.web.actions.test.TestAction  -  - runTest() - start
    12:27:56,312 INFO  [STDOUT] 29740 DEBUG myapp.test.entities.TestCallback  -  - prePersist(TestEntity) - start
    12:27:56,312 INFO  [STDOUT] 29740 DEBUG myapp.test.entities.TestCallback  -  - prePersist(TestEntity) - end
    12:27:56,347 INFO  [STDOUT] 29775 DEBUG myapp.test.web.actions.test.TestAction  -  - runTest() - end
    

    Test 2:

    public void runTest2() {
            logger.debug("runTest2() - start"); //$NON-NLS-1$
    
            String sql = "SELECT DISTINCT t FROM TestEntity t";
            Query q = this.entityManager.createQuery(sql);
    
            List<TestEntity> l = q.getResultList();
            for (int i = 0; i < l.size(); i++) {
                String x = l.get(i).getTest();
                logger.debug("runTest2() - String x=" + x); //$NON-NLS-1$
            }
    
            logger.debug("runTest2() - end"); //$NON-NLS-1$
        }
    

    Output 2:

    12:28:36,964 INFO  [STDOUT] 70392 DEBUG myapp.test.web.actions.test.TestAction  -  - runTest2() - start
    12:28:36,982 INFO  [STDOUT] 70410 DEBUG myapp.test.entities.TestCallback  -  - postLoad(TestEntity) - start
    12:28:36,982 INFO  [STDOUT] 70410 DEBUG myapp.test.entities.TestCallback  -  - postLoad(TestEntity) - end
    12:28:36,982 INFO  [STDOUT] 70410 DEBUG myapp.test.web.actions.test.TestAction  -  - runTest2() - String x=XXX
    12:28:36,983 INFO  [STDOUT] 70411 DEBUG myapp.test.web.actions.test.TestAction  -  - runTest2() - end
    

    Test 3:

    public void runTest3() {
            logger.debug("runTest3() - start"); //$NON-NLS-1$
    
            String sql = "SELECT DISTINCT t FROM TestEntity t";
            Query q = this.entityManager.createQuery(sql);
    
            List<TestEntity> l = q.getResultList();
            for (int i = 0; i < l.size(); i++) {
                l.get(i).setTest("YYY" + System.currentTimeMillis());
                this.entityManager.persist(l.get(i));
            }
            this.entityManager.flush();
            this.entityManager.clear();
    
            Random rand = new SecureRandom();
    
            q = this.entityManager.createQuery(sql);
            l = q.getResultList();
            for (int i = 0; i < l.size(); i++) {
                this.entityManager.remove(l.get(i));
            }
    
            this.entityManager.flush();
            this.entityManager.clear();
    
            logger.debug("runTest3() - end"); //$NON-NLS-1$
        }
    

    Output 3:

    12:30:00,404 INFO  [STDOUT] 153832 DEBUG myapp.test.web.actions.test.TestAction  -  - runTest3() - start
    12:30:00,407 INFO  [STDOUT] 153835 DEBUG myapp.test.entities.TestCallback  -  - postLoad(TestEntity) - start
    12:30:00,407 INFO  [STDOUT] 153835 DEBUG myapp.test.entities.TestCallback  -  - postLoad(TestEntity) - end
    12:30:00,408 INFO  [STDOUT] 153836 DEBUG myapp.test.entities.TestCallback  -  - preUpdate(TestEntity) - start
    12:30:00,408 INFO  [STDOUT] 153836 DEBUG myapp.test.entities.TestCallback  -  - preUpdate(TestEntity) - end
    12:30:00,410 INFO  [STDOUT] 153838 DEBUG myapp.test.entities.TestCallback  -  - postLoad(TestEntity) - start
    12:30:00,411 INFO  [STDOUT] 153839 DEBUG myapp.test.entities.TestCallback  -  - postLoad(TestEntity) - end
    12:30:00,414 INFO  [STDOUT] 153842 DEBUG myapp.test.entities.TestCallback  -  - preRemove(TestEntity) - start
    12:30:00,414 INFO  [STDOUT] 153842 DEBUG myapp.test.entities.TestCallback  -  - preRemove(TestEntity) - end
    12:30:00,453 INFO  [STDOUT] 153881 DEBUG myapp.test.web.actions.test.TestAction  -  - runTest3() - end
    

    解决方案

    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

    这篇关于Hibernate / JPA - 实体侦听器未正确调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆