从TransactionTemplate入手Spring事务的原理
TransactionTemplate源码
TransactionTemplate是事务处理的模板类简化了事务的使用,核心方法为execute,传入一个TransactionCallback来执行事务代码。
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager cpptm) {
return cpptm.execute(this, action);
}
else {
//获取/创建事务
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
//执行业务逻辑
result = action.doInTransaction(status);
}
catch (RuntimeException | Error ex) {
// Transactional code threw application exception -> rollback
//回滚事务
rollbackOnException(status, ex);
throw ex;
}
catch (Throwable ex) {
// Transactional code threw unexpected exception -> rollback
//回滚事务
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
//提交事务
this.transactionManager.commit(status);
return result;
}
}
由以上代码可知,TransactionTemplate通过TransactionManager来操作事务。
事务相关的类
TransactionManager
TransactionManager事务管理器,通过该类来对事务执行操作。
它的子类是PlatformTransactionManager和ReactiveTransactionManager
TransactionTemplate中使用的是PlatformTransactionManager

getTransaction方法
getTransaction方法开启了事务
本质上来说一个事务的伪代码如下:
connection.setAutoCommit(false);
try {
//执行sql
connection.commit();
} catch(Exception ex) {
connection.rollback();
}
一个事务经过以下阶段:
- 获取连接
- 准备连接,设置autoCommit为false、设置只读
- 绑定到线程变量中
- 激活同步,同步即为事务的触发器
- 使用connection
- 提交/回滚,执行钩子函数
commit/rollback方法
执行connection.commit或者rollback方法,并执行触发器
代码简化为:
prepareForCommit(status);
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
doCommit();
triggerAfterCommit(status);
triggerAfterCompletion();
TransactionSynchronizationManager
TransactionSynchronizationManager拥有一系列的线程变量
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
resources开启事务后,保存connection、sqlSession(Mybatis)等变量,
synchronizations保存了事务的同步回调,触发器保存在这个变量中
事务事件监听器
可以使用@TransactionalEventListener来向Spring容器注册一个事务监听器,注解的phase属性指定了回调的位置:
例子:
@Component
public class DataLedgerListener {
@Resource
private DataLedgerService dataLedgerService;
/**
* 监听台账编辑事件
*/
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleDataLedgerUpdate(DataLedgerUpdateEvent event) {
dataLedgerService.ledgerUpdateData(event.getDataLedgerId());
}
}
原理解析
@TransactionalEventListener本质是一个@EventListener,由EventListenerMethodProcessor处理。
EventListenerMethodProcessor扫描到带@EventListener的方法后,调用EventListenerFactory来创建一个ApplicationListener,并调用ConfigurableApplicationContext.addApplicationListener()来注册一个ApplicationListener。
@TransactionalEventListener由TransactionalEventListenerFactory创建一个TransactionalApplicationListenerMethodAdapter监听器。
TransactionalApplicationListenerMethodAdapter在监听到事件后,向TransactionSynchronizationManager的synchronizations变量中添加一个synchronization。
源码:
public void onApplicationEvent(ApplicationEvent event) {
if (TransactionalApplicationListenerSynchronization.register(event, this, this.callbacks)) {
if (logger.isDebugEnabled()) {
logger.debug("Registered transaction synchronization for " + event);
}
}
else if (this.fallbackExecution) {
if (getTransactionPhase() == TransactionPhase.AFTER_ROLLBACK && logger.isWarnEnabled()) {
logger.warn("Processing " + event + " as a fallback execution on AFTER_ROLLBACK phase");
}
processEvent(event);
}
else {
// No transactional event execution at all
if (logger.isDebugEnabled()) {
logger.debug("No transaction is active - skipping " + event);
}
}
}
随后在TransactionManager的commit方法中执行这些回调函数。
事务的使用
MyBatis对事务的使用
MyBatis对事务的封装为Transaction类

MyBatis的Executor通过Transaction.getConnection()方法获得数据库连接。
在Spring中使用mybatis时,Transaction的实现类一般使用SpringManagedTransaction,
getConnection方法的实现最终调用的是
DataSourceUtils.getConnection() 方法

对于MyBatis来说,什么时候执行事务的commit呢?
在Spring项目中不直接使用SqlSession,而是通过SqlSessionTemplate
SqlSessionTemplate通过代理sqlSession来执行commit操作。
代理逻辑:
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//首先从事务的线程变量中获取sqlSession,无法获取才会进行创建,并存入线程变量中
var sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
var result = method.invoke(sqlSession, args);
//判断sqlSession是否由Spring事务管理
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
//执行提交操作
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
var unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator
.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
//首先判断是否由Spring事务管理,是的话不执行管理,不是的话执行sqlSession.close()操作
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
}
}

浙公网安备 33010602011771号