JPA / @PostPersist @PostUpdate - 事务

Posted

技术标签:

【中文标题】JPA / @PostPersist @PostUpdate - 事务【英文标题】:JPA / @PostPersist @PostUpdate - transaction 【发布时间】:2011-06-21 05:14:23 【问题描述】:

我目前正在使用@PostPersist@PostUpdate,并且在这些触发器中我正在持久化其他实体。问题是,这些触发器是否在同一个事务中,如果不是,是否可以强制它?

对我来说,它是这样工作的。 当我查看日志时,事务不存在(它是在触发器启动之前提交的),这阻止了我(在注入 bean 的持久化方法上没有 REQUIRES_NEW)将其他实体保存在数据库中。 REQUIRED 属性完全被忽略,MANDATORY 属性不抛出异常。

这可能是 JUnit 的问题吗(因为我处于开发阶段并且没有测试完整环境的行为。)?

如果无法在此触发器上扩展事务,如何确保回滚发生在@PostPersist@PostUpdate 之前,这些操作也会被回滚。

【问题讨论】:

嘿。当我进行测试时,我看到侦听器中的所有操作都在主操作的同一事务中。我使用@PostUpdate 注解来标记监听器。 【参考方案1】:

如果您使用 Spring,您始终可以向当前事务管理器注册 TransactionSynchronization,以便在事件(例如当前运行的事务的提交)时回调:

@PostPersist
void onPersist() 
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() 

      @Override
      public void beforeCommit(boolean readOnly) 
        // do work
      
    );
      

TransactionSynchronization 还在事务成功提交之后和事务完成之前/之后提供回调。

如果您需要检查事务是否已提交或回滚,请使用afterCompletion(int status)

详情请看TransactionSynchronization's JavaDoc。

【讨论】:

2021 年 7 月更新:TransactionSynchronizationAdapter 似乎已被弃用。您可以使用 TransactionSynchronization 接口来完成工作并摆脱弃用警告!【参考方案2】:

PostPersist 事件的触发并不表示实体已成功提交。事务可以在事件触发之后但在成功提交之前回滚。 如果您在 PostPersist 中获取事务中使用的实体管理器,然后执行以下操作:

@PostPersist
void someMethod() 
  EntityManager em = null;
  em = getEntityManagerUsedInTransaction();
  EntityTransaction et = em.getTransaction(); // should return the current transaction
  if (et.isActive() ) 
    // do more db stuff
  

注意:我没有尝试过这个,所以这只是猜测(尽管我已经将生命周期事件触发器广泛用于其他东西)。 我必须补充一点,我认为这不是一个好主意。使用 PostPersist 标记其他实体应该被持久化并在另一个事务中执行。

【讨论】:

以上是关于JPA / @PostPersist @PostUpdate - 事务的主要内容,如果未能解决你的问题,请参考以下文章

@PostPersist 中修改的字段未在数据库中更新

Drupal 6.x中的hooku viewsu postu render

在wordpress中音译现有的西里尔语slug(postu name)

使用 JPA 2.1、EclipseLink、JSF 2.0 的日志表

休眠错误在@PostPersist 方法中保留一个实体

在 postPersist 事件中插入教义