Spring Hibernate,如何在事务提交或事务回滚后调用某些方法。

16

事务成功或回滚后我需要调用某个方法。我正在使用如下:

    <bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
                <property name="sessionFactory">
                    <ref local="mysessionFactory"/>
                </property>
    </bean>

    <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="mysessionFactory"/>
        </property>
    </bean>

<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
应用程序使用一些外部网络服务,需要在内部事务回滚时进行“清除”处理。 是否有方法可以在不使用声明式事务管理的情况下完成这项任务?
3个回答

28
  • 使用 Hibernate 时,您可以扩展 EmptyInterceptor 并重写 afterTransactionCompletion() 方法,在 SessionFactoryBeanHibernateTransactionManager 中注册它。

  • 使用 Spring 时,您可以扩展 TransactionSynchronizationAdapter 并重写 afterCompletion() 方法,然后在适当的时候使用 TransactionSynchronizationManager#registerSynchronization() 进行注册。

编辑

使用 Spring Aop 的示例,向所有带有 @Transactional 注释的方法添加同步。

@Aspect
class TransactionAspect extends TransactionSynchronizationAdapter {

    @Before("@annotation(org.springframework.transaction.annotation.Transactional)")
    public void registerTransactionSyncrhonization() {
        TransactionSynchronizationManager.registerSynchronization(this);

    }

    @Override
    public void afterCompletion(int status) {
        // code 
    }
}

这个功能已经实现了,因为我已经扩展了EmptyInterceptor,所以很容易实现,并且它非常适合捕获回滚。我需要解决另一个问题,即删除Web服务“清理”候选项,因为每次提交后都会调用afterTransactionCompletion()(它们可以嵌套)。因此,在响应发送到客户端之前,我无法确定整个事务链是否成功。 - Josef Prochazka
1
如果事务在范围内,您可以从TransactionAspectSupport#currentTransactionStatus()获取事务信息,但是我认为Spring仅调用一次afterCompletion()。我添加了一个示例Aspect来应用同步以进行注释驱动的事务划分。 - Jose Luis Martin
虽然“Aspect”可能适用于所有“@Transactional”方法的全局配置,但我在下面的答案中提供了基于方法的回调方法:https://dev59.com/VWAg5IYBdhLWcg3wYqJ0#43322119 - Michail Michailidis
2
TransactionSynchronizationAdapter已被弃用。 - gene b.

24

Spring有几个类可能会对这里感兴趣:

http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/transaction/support/TransactionSynchronization.html

http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/transaction/support/TransactionSynchronizationAdapter.html

http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/transaction/support/TransactionSynchronizationManager.html

这里有一些示例代码:

http://azagorneanu.blogspot.co.uk/2013/06/transaction-synchronization-callbacks.html


2016年更新

在Spring 4.2中引入的事件处理基础设施使这变得更加简单。

请参见:

https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2#transaction-bound-events

另一个受欢迎的改进是将事件的侦听器绑定到事务的阶段。 典型的例子是在事务成功完成时处理该事件。

@Component
public class MyComponent {

  @TransactionalEventListener(condition = "#creationEvent.awesome")
  public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) { 
    ...
  }

}

@TransactionalEventListener 是一个常规的 @EventListener,并且还公开了一个 TransactionPhase,在默认情况下为 AFTER_COMMIT。您还可以挂钩事务的其他阶段(BEFORE_COMMIT、AFTER_ROLLBACK 和 AFTER_COMPLETION,它只是 AFTER_COMMIT 和 AFTER_ROLLBACK 的别名)。


1
你有没有关于TransactionalEventListener如何工作/如何实现它的例子?看起来这正是我需要解决我的问题,但是关于它的文档很少。 - tallkid24
4
@tallkid24 - 这是我正在工作的项目的简要概述 https://gist.github.com/mrasband/a36cf9bedce9fe39338e2641694e3502 - nerdwaller

19

使用Spring 4+:最简单/最干净的方法是在不使用全局方面和配置的情况下,基于我在这里的回答:https://dev59.com/9mUp5IYBdhLWcg3wz58H#43322052

如果您需要在@Transactional方法成功提交后回调,只需在方法开头添加:

@Service
public class OneService {

    @Autowired
    OneDao dao;

    @Transactional
    public void a transactionalMethod() {
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter(){
            public void afterCommit(){
                //do stuff right after commit
                System.out.println("commit!!!");

            }
        });
        //do db stuff
        dao.save();
    }
}

1
感谢@Michail的回答。对于事务回滚,可以使用“afterCompletion(int status)”方法,并检查status == TransactionSynchronization.STATUS_ROLLED_BACK。 - deep
1
对于 Spring Boot 2.2.13,它已被弃用。 - Ícaro Erasmo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接