事务提交Spring JPA之后的事件

Ysa*_*sak 3 hibernate jpa spring-mvc java-ee spring-transactions

我需要在成功的事务提交之后执行一些特定的操作,这基本上包括我对数据的分析操作;

我尝试使用以下代码段

public class EntityEventHandlers {
    private static Logger logger = LoggerFactory.getLogger(EntityEventHandlers.class);

    @Autowired
    private AsyncEventBus async;

    @PostUpdate
    public void postUpdate(Order order) {
        AutowireHelper.autowire(this, this.async);
        logger.debug("post update called " + order.getId());
        async.post(new ESCreateOrderEvent(order));
    }

    @PostPersist
    public void postPersist(Order order) {
        AutowireHelper.autowire(this, this.async);
        logger.debug("post insert called " + order.getId());
        async.post(new ESCreateOrderEvent(order));
    }
}
Run Code Online (Sandbox Code Playgroud)

但发现,当我的订单没有坚持.

有人可以告诉我一个更好的解决方案,我可以在事务提交成功后触发一些操作.

我听说(尝试使用)关于@TransactionEventListener,但没有看到任何触发.

更新了源

@Component
public class TXEventHandler {
    @TransactionalEventListener
    public void doAfterCommit(ApplicationEvent event){
        //process here
    }
}
Run Code Online (Sandbox Code Playgroud)

关于应用程序它是一个基于4.2.0的Spring MVC,并使用Hibernate和MySql作为db.

现在我已经通过将事件放入延迟队列来解决问题,并且延迟足以发生数据库提交.但我知道这不是一个好的解决方案.如果有人遇到此问题并能够解决问题,请告诉我.

提前致谢.

小智 6

假设,正如您的评论所提到的,您正在使用实体管理器来持久化/合并您的实体对象,您可能有一个Bean连接它.如果是这样,那么为了利用@TransactionalEventListener,您希望连接ApplicationEventPublisher豆.你的课可能看起来像:

@Component
public class OrderManager {
    @PersistenceContext
    protected EntityManager entityManager;

    // You need this Spring bean
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    // ...
    @Transactional
    public void saveOrder(Order newOrder) {
        entityManager.persist(newOrder);
        applicationEventPublisher.publishEvent(new OrderEvent());
    }

    @TransactionalEventListener
    public void doAfterCommit(OrderEvent event){
        //process here
    }

    // inner class for brevity, you may not want to do this in practice
    public static class OrderEvent {
    }   
}
Run Code Online (Sandbox Code Playgroud)

这段代码(尽管可怕地放在一个类中......)只是为了说明这一点:如果你想要触发@TransactionalEventListener,那么你需要(至少):

  1. 在Spring托管bean中定义它
  2. 连接@Transactional所在的"ApplicationEventPublisher"(在步骤1中不必是同一个bean)
  3. 在@Transactional方法中调用"applicationEventPublisher.publishEvent()"

提交完成后,默认行为将触发TransactionalEventListener并刷新实体管理器,但仍在事务的范围内.您可以使用"阶段"参数在注释中更改此值,但这应该足以解决您的问题.

PS.您可以从https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2中收集大部分内容,如JB Nizet所说