前言:
众所周知, Spring实现事务控制是在方法上添加注解Transactional来实现的。例如: @Transactional(rollbackFor = Exception.class) 当我们的业务逻辑代码抛出异常时,Spring 会捕获到异常,并检验其是否在rollbackFor中【默认是运行时异常】,并判断是否执行回滚操作。
技术先知:
当我们在了解Spring事务控制原理之前先来了解一下Spring控制事务常用类:
- PlatformTransactionManager接口,事务管理定义接口,实现Spring事务事务管理,该接口需要被实现:
- TransactionDefinition 事务定义:包含事务的隔离级别、传播属性等等:
- TransactionStatus : 事务的状态。
PlatformTransactionManager:
public interface PlatformTransactionManager {
// 创建新事务或返回当前事务(事务嵌套时,根据隔离级别不同,返回不同)
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
// 提交事务
void commit(TransactionStatus status) throws TransactionException;
// 回滚事务
void rollback(TransactionStatus status) throws TransactionException;
}
TransactionDefinition
public interface TransactionDefinition {
/**
* 类型: 支持当前事务
* 解释: 如果当前没有事务,就新建一个事务,如果有事务,就加入其中
*/
int PROPAGATION_REQUIRED = 0;
/**
* 类型: 支持当前事务
* 解释: 支持当前事务,如果没有事务,则以非事务的形式执行
*/
int PROPAGATION_SUPPORTS = 1;
/**
* 类型: 支持当前事务
* 解释: 支持当前事务,如果没有事务,就抛出异常
*/
int PROPAGATION_MANDATORY = 2;
/**
* 类型: 不支持当前事务
* 解释: 新建事务,如果存在事务,就将事务挂起,新建一个事务
*/
int PROPAGATION_REQUIRES_NEW = 3;
/**
* 类型: 不支持当前事务
* 解释: 以非事务的方式执行,当前存在事务,就把当前事务挂起
*/
int PROPAGATION_NOT_SUPPORTED = 4;
/**
* 类型: 不支持当前事务
* 解释: 以非事务的方式执行,如果当前有事务,则抛出异常
*/
int PROPAGATION_NEVER = 5;
/**
* 类型: 事务嵌套
* 解释: 如果当前存在事务,则在嵌套事务中执行;如果当前没有事务,则执行与Propagation. REQUIRED类似的操作
*/
int PROPAGATION_NESTED = 6;
/**
* 类型 :Default
* 解释: 默认的事务隔离级别,默认是用数据库的事务隔离级别
*/
int ISOLATION_DEFAULT = -1;
/**
* 类型:未提交读
* 解释: 脏读,不可重复读、幻读都存在
*/
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
/**
* 类型: 已提交读
* 解释: 避免脏读,但是存在不可重复读,幻读
*/
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
/**
* 类型: 可重复读
* 解释: 避免脏读和不可重复读,但是有幻读的可能
*/
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
/**
* 类型: 串行化
* 解释: 避免以上所有读的问题
*/
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
int TIMEOUT_DEFAULT = -1;
int getPropagationBehavior();
int getIsolationLevel();
int getTimeout();
boolean isReadOnly();
String getName();
}
TransactionStatus
public interface TransactionStatus extends SavepointManager, Flushable {
// 是否是新事务
boolean isNewTransaction();
// 是否有保存节点
boolean hasSavepoint();
// 仅设置事务回滚
void setRollbackOnly();
// 是否被标记仅设置事务回滚
boolean isRollbackOnly();
// 刷新到数据存储区
@Override
void flush();
// 返回此事务是否已完成 【提交或回滚】
boolean isCompleted();
}
运行时源码:
上述是关于Spring 对事务管理的制定的相关规则,那到我们配置了Transactional 注解后,Spring究竟执行了那些代码,怎么实现的 具体功能,那我们来具体看一下 TransactionInterceptor 和 TransactionAspectSupport 【TransactionInterceptor 继承 TransactionAspectSupport 】 :
org.springframework.transaction.interceptor.TransactionInterceptor#invoke:
public Object invoke(final MethodInvocation invocation) throws Throwable {
// 业务逻辑对象
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 调用 TransactionAspectSupport 对象中的方法
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction:
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// 1. 获取事务管理器
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// 开启事务,获取到事务对象,并设置连接 AutoCommit = False
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 执行我们的业务逻辑代码 Service
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 捕获异常,判断时候需要回滚,并将异常继续抛出。
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 重置事务对象信息
cleanupTransactionInfo(txInfo);
}
// 无异常,提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// 省略....
}
}
根据 invokeWithinTransaction 可以看出整个事务控制、和业务逻辑代码的调用 在其方法内已全部完成,由于Spring源码的黑深林过于复杂,本篇博文没有去过多的深入源码,有兴趣的小伙伴可以 Debug 向源码中仔细阅读,Spring 事务源码简单理解也就是:
- 获取事务控制信息 :Transaction tx=session.getTransaction();
- 开启事务,设置自动提交False:session.beginTransaction();
- 提交事务:tx.commit();
- 回滚事务:tx.rollback();
需要注意的是,事务的回滚与提交是由数据库来实现的,Spring只不过调用其方法而已。