Hibernate/JPA - 未正确调用实体侦听器

Sha*_*man 6 hibernate seam jpa callback entitylisteners

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

@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;
...
}
Run Code Online (Sandbox Code Playgroud)

以及以下EntityListener回调类:

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$
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,当我运行测试时,我没有看到所有的回调方法都按照我的预期被调用.我运行了以下场景的测试:

  • 坚持一个新的项目
  • 更新现有项目
  • 加载项目
  • 删除项目

但是,我看到的唯一回调是:

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

剩余的回调没有按预期执行.这是正常行为吗?我只是误解了吗?这与Seam管理交易的方式有关吗?或者,我是不是做对了?

我很感激你能给予的任何帮助.

编辑: 根据要求,这是我正在调用的确切代码和我收到的输出:

测试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$
}
Run Code Online (Sandbox Code Playgroud)

输出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
Run Code Online (Sandbox Code Playgroud)

测试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$
    }
Run Code Online (Sandbox Code Playgroud)

输出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
Run Code Online (Sandbox Code Playgroud)

测试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$
    }
Run Code Online (Sandbox Code Playgroud)

输出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
Run Code Online (Sandbox Code Playgroud)

Seb*_*ber 8

对不起,如果我给出了错误的答案......我不知道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后面,并查看注册了哪些事件监听器.那个申请你一个人吗?如果有人试图注册自定义/遗留事件监视器或其他东西,他可能已经覆盖了JPA事件监视器.

这可以通过以下方式实现:

EntityManager em = ...
Session session = (Session)em.getDelegage()
SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl)session.getSessionFactory();
EventListeners el = sessionFactoryImpl.getEventListeners()
Run Code Online (Sandbox Code Playgroud)

然后你可以看看里面是什么,例如,根据你的问题,你可以比较:

el.getPreLoadEventListeners()
el.getPreDeleteEventListeners()
Run Code Online (Sandbox Code Playgroud)

并记住"默认行为"是: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会很好