因为Spring声明式事务是通过AOP增强实现的,所以现在具体来分析一下Spring事务的执行过程,因为AOP是通过拦截器执行链实现的,所以我们可以把关注点聚焦在拦截器上-TransactionInterceptor
@Transactional
public void insertUser(String name,int age){
userMapper.insertUser(name,age);
}
@Test
public void insertUser(){
userService.insertUser("test",123);
}
/**
* @param invocation 拦截器链的执行器,用于执行下一个拦截器
* @return 返回连接点的执行结果
* @throws Throwable
*/
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
//获取被代理对象的类类型
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
//调用父类TransactionAspectSupport方法
//传入连接点方法对象,代理对象类类型,拦截器执行器MethodInvocation的proceed()方法引用
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
/** 执行事务逻辑
* @param method 连接点的方法对象
* @param targetClass 被代理的对象,用于执行method
* @param invocation 用于执行下一个拦截器
* @return the return value of the method, if any
* @throws Throwable propagated from the target invocation
*/
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
//事务注解属性源,包含了保存 事务注解属性的缓存 如果为空不执行事务
TransactionAttributeSource tas = getTransactionAttributeSource();
//事务注解属性对象
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
//事务管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
//获取连接点唯一标识字符串 com.example.UserService.insertUser()
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
//如果是本地事务执行逻辑
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
//创建事务并返回事务对象信息
//TransactionInfo 事务信息对象 主要包含 TransactionStatus TransactionAttribute PlatformTransactionManager
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
//执行下一个拦截器,如果只有一个拦截器,那么下一个会执行连接点的方法()
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
//事务回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//清除事务信息
cleanupTransactionInfo(txInfo);
}
//提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
......
}
/**
* 如果需要则创建事务,需要根据事务传播级别来判断是否创建事务
* @param txAttr the TransactionAttribute (may be {@code null})
* @param joinpointIdentification 连接点执行方法的唯一标识
* @return a TransactionInfo object, whether or not a transaction was created.
* The {@code hasTransaction()} method on TransactionInfo can be used to
* tell if there was a transaction created.
* @see #getTransactionAttributeSource()
*/
@SuppressWarnings("serial")
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
//如果没有执行名称,则使用joinpointIdentification,并返回代理对象
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
TransactionStatus status = null;
//事务属性不为null
if (txAttr != null) {
//事务管理器不为null
if (tm != null) {
//获取事务
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
//创建并初始化TransactionInfo
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
/**
* This implementation handles propagation behavior. Delegates to
* {@code doGetTransaction}, {@code isExistingTransaction}
* and {@code doBegin}.
* @see #doGetTransaction
* @see #isExistingTransaction
* @see #doBegin
*/
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
//返回DataSourceTransactionObject 持有ConnectionHolder 数据库连接
//如果当前线程已经存在事务,则会从ThreadLocal的Map 以DataSource为key获取ConnectionHolder
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
//当前线程是否存在事务
if (isExistingTransaction(transaction)) {
//根据事务隔离传播处理事务
return handleExistingTransaction(definition, transaction, debugEnabled);
}
//注意:以下处理逻辑为不存在事务
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
//事务传播级别为PROPAGATION_MANDATORY,不存在事务抛出异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
//以下事务传播级别,在当前不存在事务的情况下,统一创建新的事务
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//创建status
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
//开启事务 获取连接 设置数据库事务隔离级别 设置超时时间 绑定连接资源到本地线程
doBegin(transaction, definition);
//初始化事务同步器TransactionSynchronizationManager
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
//如果不是以上四种支持事务的传播级别,
//即为PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER
//这三种传播级别以非事务的方式执行
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + definition);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
/**
* This implementation sets the isolation level but ignores the timeout.
*/
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
//从数据源获取新的连接
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
//设置 数据库事务隔离界别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
//设置为 不自动提交事务 即开启事务
con.setAutoCommit(false);
}
//设置 只读事务
prepareTransactionalConnection(con, definition);
//设置事务为生效的
txObject.getConnectionHolder().setTransactionActive(true);
//设置连接的超时时间
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// 绑定新的连接到本地线程 key为对应的数据源
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
......
try {
//执行下一个拦截器,如果只有一个拦截器,那么下一个会执行连接点的方法()
retVal = invocation.proceedWithInvocation();
}
//捕获连接点抛出的异常
catch (Throwable ex) {
//事务回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
........
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
//使用RuleBasedTransactionAttribute判断当前异常是否需要回滚-如果注解上定义了@Transactional(rollbackFor = Exception.class)
//这里会使用ex向上递归查找父类是否和Exception是否相同,如果相同则进行回滚
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
//否则执行提交
else {
//commit() 会判断通过手动设置回滚的操作,然后也会进行回滚
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}
public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
//如果执行了TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
//这里会判断为true并且进行回滚操作
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
//通过ConnectHolder setRollbackOnly() 设置的回滚
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
//执行提交
processCommit(defStatus);
}
@Transactional
public void insertUser(String name,int age) throws Exception {
userMapper.insertUser(name,age);
//手动回滚
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
}
@Test
public void insertUser() throws Exception {
userService.insertUser("test",123);
//查询结果
userService.selectUser();
}
[{ID=1, NAME=小明, AGE=23}, {ID=2, NAME=小白, AGE=24}]
22:58:09.131 [main] DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Transactional code has requested rollback
以上回滚日志对应到
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
.........
try {
//执行下一个拦截器,如果只有一个拦截器,那么下一个会执行连接点的方法()
retVal = invocation.proceedWithInvocation();
}
//捕获连接点抛出的异常
catch (Throwable ex) {
//事务回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//清除事务信息
cleanupTransactionInfo(txInfo);
}
//提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
//如果执行了TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
//这里会判断为true并且进行回滚操作
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
//通过ConnectHolder setRollbackOnly() 设置的回滚
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
//执行提交
processCommit(defStatus);
}