概述
业务上经常会有一些需求是需要在某个数据库操作事务提交之后再去操作。
我常用的就方式有@TransactionalEventListener
和TransactionSynchronizationManager
.
其实@TransactionalEventListener
背后使用的也是TransactionSynchronizationManager
。
注意点:在afterCompletion
方法中已经脱离当前事务了,如果想确保其中的方法也在一个事务中,那么就需要开启一个新事务.
在使用 >= spring 5.2
是可以用org.springframework.transaction.support.TransactionTemplate#execute
方法,里面会新开启一个事务。在小于上述版本时,可以手动开启事务来控制.
使用demo
//fallbackExecution = true代表没有事务的时候也监听
@TransactionalEventListener(value = {xxx.class}, fallbackExecution = true)
@Order(Ordered.HIGHEST_PRECEDENCE)
public void onApplicationEvent(xxx event) {
log.info("监听成功,xxxxxx");
//xxxxx
}
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCompletion(int status) {
switch (status) {
case 0:
// 外部方法事务提交后执行的业务逻辑
break;
case 1:
// 外部方法事务回滚后执行的业务逻辑
break;
case 2:
// 外部方法事务异常时执行的业务逻辑
break;
}
TransactionSynchronization.super.afterCompletion(status);
}
});
TransactionSynchronizationManager(事务同步器)分析
平时使用的时候都是直接用注解@Transactional
,一般也知道是spring aop
帮我们开启了事务,其中aop
拦截使用事务注解的方法后使用的就是TransactionSynchronizationManager
.
我用的是mybatis-spring-2.0.7
,就从mybtais
获取connection
来入手了
org.mybatis.spring.transaction.SpringManagedTransaction#openConnection
在从连接池获取connection
的时候会判断是否开启了事务,如果已开启,那么会将连接暂时绑定到事务同步管理器中.
所谓的绑定其实就是塞到了一个threadLocal
中和当前线程进行了一个关联。
业务中对事务的扩展方法通常都是在TransactionSynchronization
的方法中执行的.
在org.springframework.transaction.support.AbstractPlatformTransactionManager#triggerAfterCompletion
中可以看到会将所有之前注册的同步事务操作按照List
中的顺序(注册顺序)依次调用.
最后在org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit
中的finally
中可以看到对各项资源进行了释放,意味着我们仍旧可以在这之前拿到connection
连接进行操作db
获取连接绑定connection给TransactionSynchronizationManager
TransactionSynchronization 扩展点
public interface TransactionSynchronization extends Ordered, Flushable {
/** Completion status in case of proper commit. */
// 事务提交状态
int STATUS_COMMITTED = 0;
/** Completion status in case of proper rollback. */
// 事务回滚状态
int STATUS_ROLLED_BACK = 1;
/** Completion status in case of heuristic mixed completion or system errors. */
// 事务异常状态
int STATUS_UNKNOWN = 2;
/**
* 当前事务挂起时触发
* Supposed to unbind resources from TransactionSynchronizationManager if managing any.
* @see org.springframework.transaction.reactive.TransactionSynchronizationManager#unbindResource
*/
default void suspend() {
}
/**
* 当前事务恢复时触发(结束挂起时)
* Supposed to rebind resources to TransactionSynchronizationManager if managing any.
* @see org.springframework.transaction.reactive.TransactionSynchronizationManager#bindResource
*/
default void resume() {
}
/**
* 当前事务刷新时触发
* 将基础会话刷新到数据存储区(如果适用),比如Hibernate/JPA的Session
* @see org.springframework.transaction.TransactionStatus#flush
*/
@Override
default void flush() {
}
/**
* 当前事务提交前触发,此处若发生异常,会导致回滚。
* @see #beforeCompletion
*/
default void beforeCommit(boolean readOnly) {
}
/**
* 当前事务完成前触发。
* 在beforeCommit之后,commit/rollback之前执行。即使异常,也不会回滚。
* @see #beforeCommit
* @see #afterCompletion
*/
default void beforeCompletion() {
}
/**
* 当前事务提交后触发
*/
default void afterCommit() {
}
/**
* 当前事务完成后触发
* 通过status的value指定具体的触发时机(即上面的三个属性)
*/
default void afterCompletion(int status) {
}
}