当前位置: 首页 > 面试题库 >

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

赵晟睿
2023-03-14
问题内容

我试图在我的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;
...
}

以及以下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$
    }
}

但是,当我运行测试时,我没有看到我期望的所有回调方法都被调用。我已经对以下情况进行了测试:

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

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

  • @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$
}

输出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

测试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$
    }

输出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

测试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$
    }

输出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

问题答案:

抱歉,如果我给出错误的答案…我不知道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()

然后您可以查看内部内容,例如,根据您的问题,您可以进行比较:

el.getPreLoadEventListeners()
el.getPreDeleteEventListeners()

并记住“默认行为”是: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,那就太好了



 类似资料:
  • 问题内容: 如何启用处理JPA回调的Hibernate事件侦听器? 当前,我正在将Hibernate 4与SessionFactory配置一起使用,但是当我保留一个对象时,JPA回调无法正常运行。 任何建议都是最欢迎的。 源代码 临时实体类: TempVal类: MainClass类: Hibernate配置: 程序输出 程序输出如下: 预期的输出将是: 问题答案: 这个问题基本上是一样的。 事实

  • 问题内容: 我需要将Spring依赖项注入到JPA实体侦听器中。我知道我可以使用@Configurable和Spring的AspectJ weaver作为javaagent来解决此问题,但这似乎是一个棘手的解决方案。还有其他方法可以完成我想做的事情吗? 问题答案: 另一个技巧是用静态方法实现实用程序类,该实用程序类可帮助您不仅在托管类中在任何地方使用Spring Bean:

  • 我有一个EAR应用程序(要部署在WebLogic12c上),它有一个“持久化”组件。“persist”组件使用JPA(实现:EclipseLink)来持久化对象。 使用entityManager的bean声明为,实体管理器通过注释注入。 问题是,我每次尝试访问entityManager时都有一个(意思是他没有被正确注入)。 persistence.xml 我在常规代码中是这样使用的: MyBean

  • 无法提交JPA事务;嵌套异常是javax.persistence.RollBackException:提交事务时出错 是否可以在PostPersisted方法中保存此operationHistoryEntity对象?我想我可以用@EntityListeners注释实体,然后将数据库中关于新的、修改的或删除的记录的信息保存到OperationHistory表中。

  • 问题内容: 我在互相嵌套时想调用侦听器时遇到问题。我也尝试过,但是遇到了同样的问题。 为了演示问题,我将代码简化为问题。有两个按钮,第一个位于第一个ui:repeat内部,将成功的调用为简单的侦听器。第二个按钮位于嵌套的ui:repeat元素内部,应调用与第一个按钮相同的侦听器,但永远不会调用该侦听器。 你能告诉我这怎么了吗? 问题答案: 这是一个已知的Mojarra问题,涉及到的中断状态管理。特

  • 我有一个简单的HibernateInterceptor,基本上我想自动设置几个字段。此拦截器(如下所示)扩展了EmptyInterceptor: 我使用spring配置文件进行布线,如下所示: 但是,永远无法到达拦截器。有人有什么线索吗?我还尝试将以下内容添加到事务管理器bean定义中,如下所示: