> 文档中心 > 深入理解@Transactional注解的使用和原理

深入理解@Transactional注解的使用和原理

目录

1.TransactionInterceptor实现拦截

2.TransactionAspectSupport切面

2.1 createTransactionIfNecessary方法

2.1.2 getTransaction()方法

2.1.3 prepareTransactionInfo方法

2.1.4 小节:

2.2 调用目标方法

2.3 completeTransactionAfterThrowing方法

2.4 commitTransactionAfterReturning方法

总结:


@Transactional声明式事务的具体使用方法这里不再重复说明,大家可以参考上一篇文章;

本文主要是带着大家一起看一下@Transactional注解的源码,包括传播机制的实现;

测试案例:下面这两个方法是不同类之间方法调用,并且都加了@Transactional注解的;

    @Transactional    public void methodA(){ userMapper.selectById("jzcs"); infoService.methodB("userId");    }    //methodB是infoService的方法    @Transactional    public void methodB(String userId){ infoMapper.selectUserClassInfo(userId);    }

我们知道@Transactional是基于aop实现的,那么必定有拦截器和切面;

1.TransactionInterceptor实现拦截

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {    @Nullable    public Object invoke(MethodInvocation invocation) throws Throwable { Class targetClass = invocation.getThis() != null ?      AopUtils.getTargetClass(invocation.getThis()) : null; Method var10001 = invocation.getMethod(); invocation.getClass(); return this.invokeWithinTransaction(var10001, targetClass, invocation::proceed);    }}

TransactionInterceptor会拦截加了@transactional注解的方法,再调用目标方法前,会调用TransactionAspectSupport的invokeWithinTransaction方法对目标方法进行争强;

2.TransactionAspectSupport切面

既然是基于aop,肯定少不了切面对目标方法进行增强了,TransactionAspectSupport.invokeWithinTransaction方法就是对目标前,创建事务和数据库连接,在目标方法执行后,提供事务的提交和回滚,我们看下面源码大家就清楚了:

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {    @Nullable    protected Object invokeWithinTransaction(Method method, @Nullable Class targetClass, TransactionAspectSupport.InvocationCallback invocation) throws Throwable { //获取@Transactional注解定义的的一些属性(包括隔离级别,传播机制等) TransactionAttributeSource tas = this.getTransactionAttributeSource(); TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null; //创建一个dataSourceTransactionManager,包含数据库信息等 PlatformTransactionManager tm = this.determineTransactionManager(txAttr);  //获取目标方法的方法名(就是切点) String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr); Object result; if(){     //省略一部分无关紧要的代码 }else{     //这个很重要,包含有事务和数据库连接等相关信息     TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);     result = null;     try {  //调用目标方法,访问数据库和业务逻辑处理等  result = invocation.proceedWithInvocation();     } catch (Throwable var17) {  //如果调用目标方法报错了,处理回滚  this.completeTransactionAfterThrowing(txInfo, var17);  throw var17;     } finally {  this.cleanupTransactionInfo(txInfo);     }     //如果调用目标方法没有报错并成功返回,就提交事务     this.commitTransactionAfterReturning(txInfo);     return result; }}

只要大家对切面编程aop了解的话,上面的代码就很清晰它的功能了,就是类似于一个环绕通知;

接下来我们就详细了解一下几个具体的方法:

1.createTransactionIfNecessary();创建事务,包含数据库的连接和事务状态等信息;

2.completeTransactionAfterThrowing();调用目标方法报错,回滚;

3.commitTransactionAfterReturning();调用目标方法成功,提交事务(里面有一些判断,不符合条件可能会回滚)

2.1 createTransactionIfNecessary方法

createTransactionIfNecessary()看方法名称就知道,是创建事务,事务包含一些事务本身的信息(传播机制、隔离级别、是否只读、事务的状态、以及数据库连接等)

protected TransactionAspectSupport.TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final String joinpointIdentification) { //省略部分不重要的代码 TransactionStatus status = null; if (txAttr != null) {     if (tm != null) {    //创建一个TransactionStatus类型的对象,这个很重要,后面详解  status = tm.getTransaction((TransactionDefinition)txAttr);     } else if (this.logger.isDebugEnabled()) {  this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured");     } } //封装并返回TransactionAspectSupport.TransactionInfo类型的对象,这个包含了事务的所有信息 return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr, joinpointIdentification, status);    }

如上面代码所示,createTransactionIfNecessary方法创建封装了TransactionAspectSupport.TransactionInfo类型的对象,该对象中包含了事务的所有信息;下面我们就来看里面调用的两个方法:

1.tm.getTransaction(),创建一个TransactionStatus类型的对象,里面包含数据库连接信息和事务状态信息;

2.this.this.prepareTransactionInfo(),封装并返回TransactionAspectSupport.TransactionInfo类型的对象,这个包含了事务的所有信息

2.1.2 getTransaction()方法

调用的是AbstractPlatformTransactionManager类getTransaction方法返回transactionStatus;

该方法做的事情比较多,创建数据库连接,维护TransactionSynchronizationManager的线程变量等

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException { //调用AbstractPlatformTransactionManager的dogetTransaction方法获取事务datasourceTransactionManager.dataSourceTransactionObject类型的txOBject(里面包含有connectionHolder,只不过第一次为空) Object transaction = this.doGetTransaction();  //isExistingTransaction方法用于判定上面的transaction是否从TransactionSynchronizationManager的线程变量resources中获取到connectionHolder,如果获取到了为true,表明是共用同一个事务 if (this.isExistingTransaction(transaction)) {     return this.handleExistingTransaction((TransactionDefinition)definition, transaction, debugEnabled); //判断事物的过期时间 } else if (((TransactionDefinition)definition).getTimeout() < -1) {     throw new InvalidTimeoutException("Invalid transaction timeout", ((TransactionDefinition)definition).getTimeout());  //如果当前事务的传播策略是2,也就是PROPAGATION_MANDATORY,中文翻译为强制,支持使用当前事务,如果当前事务不存在,则抛出Exception。 } else if (((TransactionDefinition)definition).getPropagationBehavior() == 2) {     throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'"); //如果当前事务的传播策略不是0、默认事务,3、REQUIRES_NEW 创建新事务,6、NESTED:嵌套事务,就走下面的方法 } else if (((TransactionDefinition)definition).getPropagationBehavior() != 0 && ((TransactionDefinition)definition).getPropagationBehavior() != 3 && ((TransactionDefinition)definition).getPropagationBehavior() != 6) {     if (((TransactionDefinition)definition).getIsolationLevel() != -1 && this.logger.isWarnEnabled()) {  this.logger.warn("Custom isolation level specified but no actual transaction initiated; isolation level will effectively be ignored: " + definition);     }     boolean newSynchronization = this.getTransactionSynchronization() == 0;     return this.prepareTransactionStatus((TransactionDefinition)definition, (Object)null, true, newSynchronization, debugEnabled, (Object)null); } else {     //我们的传播策略是0,默认策略,走下面的代码     AbstractPlatformTransactionManager.SuspendedResourcesHolder suspendedResources = this.suspend((Object)null);     if (debugEnabled) {  this.logger.debug("Creating new transaction with name [" + ((TransactionDefinition)definition).getName() + "]: " + definition);     }     try {  //newSynchronization为true  boolean newSynchronization = this.getTransactionSynchronization() != 2;  //newTransactionStatus创建一个transactionStatus对象,表事务的相关状态  DefaultTransactionStatus status = this.newTransactionStatus((TransactionDefinition)definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);  //doBegin方法很重要,封装transaction,我们下面详细说明  this.doBegin(transaction, (TransactionDefinition)definition);  //prepareSynchronization是维护TransactionSynchronizationManager的线程变量,TransactionSynchronizationManager很重要,我们下面也会详细说明  this.prepareSynchronization(status, (TransactionDefinition)definition);  return status;     } catch (Error | RuntimeException var7) {  this.resume((Object)null, suspendedResources);  throw var7;     } }    }

我们重点讲解doGetTransaction方法、doBegin方法、prepareSynchronization方法:

2.1.2.1 doGetTransaction方法

该方法是尝试从TransactionSynchronizationManager的线程变量resources里面获取connectionHolder即数据库连接,第一个方法肯定是null,但是后续被调用方法共用一个事务的话,就可以从resources里面获取相同的connectionHolder;

protected Object doGetTransaction() { //创建DataSourceTransactionManager的内部类DataSourceTransactionObject对象 DataSourceTransactionManager.DataSourceTransactionObject txObject = new DataSourceTransactionManager.DataSourceTransactionObject(); txObject.setSavepointAllowed(this.isNestedTransactionAllowed()); //尝试从TransactionSynchronizationManager类的线程变量resources里面获取connectionHolder,即获取数据库连接,第一次conHolder肯定为null ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(this.obtainDataSource()); txObject.setConnectionHolder(conHolder, false); return txObject;    }

2.1.2.2  doBegin方法

实际调用的DataSourceTransactionManager的doBegin方法,做了下面几件事

1.调用dataSource.getConnection方法获取数据库连接connection

2.将connection封装入ConnectionHolder,并设置synchronizedWithTransaction为true,并将connectionHolder封装到datasourceTransactionManager.dataSourceTransactionObject类型的txOBject对象里面

3.调用dataSourceUtils.prepareConnectionForTransaction方法从注解属性中获取相关值并设置相关属性:

        3.1设置数据库连接的事务隔离级别transactionalIsolation,

        3.2设置自动提交autoCommit为false,

        3.3设置timeout事务过期时间,

        3.4设置transactionActive为true

4.将connectionHolder存入TransactionSynchronizationManager的resources,以dataSources为key

下面看源码:

protected void doBegin(Object transaction, TransactionDefinition definition) { DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)transaction; Connection con = null; try {     //第一次肯定没有connectionHolder     if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {     //第一次肯定需要从数据库连接池中获取数据库连接  Connection newCon = this.obtainDataSource().getConnection();      //将数据库连接封装到ConnectionHolder对象中  txObject.setConnectionHolder(new ConnectionHolder(newCon), true);     }     //下面的代码就是一些封装了     txObject.getConnectionHolder().setSynchronizedWithTransaction(true);     con = txObject.getConnectionHolder().getConnection();     Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);     txObject.setPreviousIsolationLevel(previousIsolationLevel);     if (con.getAutoCommit()) {  txObject.setMustRestoreAutoCommit(true);  }     //因为是事务,所以不再自动提交  con.setAutoCommit(false);     }     //该方法无关紧要     this.prepareTransactionalConnection(con, definition);     //表示当前数据库连接用于事务     txObject.getConnectionHolder().setTransactionActive(true);     int timeout = this.determineTimeout(definition);   //设置自定义的事务超时时间     if (timeout != -1) {  txObject.getConnectionHolder().setTimeoutInSeconds(timeout);     }     //当前的connectionHolder肯定是新的,会走下面的代码     if (txObject.isNewConnectionHolder()) {  //该方法将connectionHolder存入TransactionSynchronizationManager的resources,以dataSources为key,后续被调用方法如果共用一个事务,就会从TransactionSynchronizationManager获取到这个connectionHolder,也就是共用一个连接了TransactionSynchronizationManager.bindResource(this.obtainDataSource(), txObject.getConnectionHolder());     } } catch (Throwable var7) {     //省略部分代码 }    }

综上,doBegin方法获取了数据库连接封装connectionHoler,和事务绑定,并保存在线程变量TransactionSynchronizationManager.resources中;这个步骤很重要,因为后续访问数据库,就会从线程变量中获取connectionHoler,也就获取数据库连接;被调用方法如果是共用一个事务,也会从该connectionHolder中获取连接,即共用一个事务,就会共用一个数据库连接;

上面提到了TransactionSynchronizationManager类,我们这里看一下这个类有什么?

public abstract class TransactionSynchronizationManager {    //存有connectionHolder(当前事务的数据库连接)和sqlSessionHoler(后续访问数据库的会话)    private static final ThreadLocal<Map> resources = new NamedThreadLocal("Transactional resources");    //LinkedHashSet  后面访问数据库会存sqlsessionSynchronization对象,属性是sqlsessionFactory和sqlsessionHolder(数据库会话信息)    private static final ThreadLocal<Set> synchronizations = new NamedThreadLocal("Transaction synchronizations");    //当前事务的名称,对应@Transaction的transactionManager,没有的话就取方法的全类名    private static final ThreadLocal currentTransactionName = new NamedThreadLocal("Current transaction name");    //当前事务是否是只读事务   false    private static final ThreadLocal currentTransactionReadOnly = new NamedThreadLocal("Current transaction read-only status");    //当前事务的隔离级别    private static final ThreadLocal currentTransactionIsolationLevel = new NamedThreadLocal("Current transaction isolation level"); //是否有事务 true    private static final ThreadLocal actualTransactionActive = new NamedThreadLocal("Actual transaction active");}

显然这个类里面含有很多线程变量,很多面试官都会问,事务的数据库连接信息是保存在哪里的啊?就是在这个TransactionSynchronizationManager的resources里面;

2.1.2.3 prepareSynchronization方法

如下代码所示,该方法旨在封装TransactionSynchronizationManager的线程变量;具体里面的属性上面已经说明了哈;

protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) { //isNewSynchronization为true if (status.isNewSynchronization()) {     TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());     TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(definition.getIsolationLevel() != -1 ? definition.getIsolationLevel() : null);     TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());     TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());     TransactionSynchronizationManager.initSynchronization(); }    }

综上:整个tm.getTransaction方法,最重要的就是获取到数据库连接,维护了TransactionSynchronizationManager类里面的线程变量,并将数据库连接同事务绑定,封装一个TransactionStatus对象;

2.1.3 prepareTransactionInfo方法

该方法将得到的数据包括TransactionStatus、DataSourceTransactionManager tm、TransactionAttribute txAttr等封装成TransactionAspectSuport.TransactionInfo对象并返回;

protected TransactionAspectSupport.TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, String joinpointIdentification, @Nullable TransactionStatus status) {  //封装TransactionAspectSupport.TransactionInfo txInfo对象 TransactionAspectSupport.TransactionInfo txInfo = new TransactionAspectSupport.TransactionInfo(tm, txAttr, joinpointIdentification); if (txAttr != null) {   txInfo.newTransactionStatus(status); } else if (this.logger.isTraceEnabled()) {     //省略无关紧要的代码 } //该方法的作用暂时不清楚 txInfo.bindToThread(); return txInfo;    }

2.1.4 小节:

整个createTransactionIfNecessary()方法旨在:
1.获取数据库连接封装connectionHolder;

2.维护TransactionSynchronizationManager类里面的线程变量,比如将数据库连接信息存入线程变量resources中;

3.封装TransactionStatus对象;

4.封装TransactionAspectSupport.TransactionInfo并返回;

2.2 调用目标方法

Object var8 = invocation.proceedWithInvocation();

这个就是mybatis的内容了,还是有需要提到的地方就是在调用数据库的时候SpringManagedTransaction类的openConnection方法获取数据库连接

private void openConnection() throws SQLException { //获取数据库连接 this.connection = DataSourceUtils.getConnection(this.dataSource); this.autoCommit = this.connection.getAutoCommit(); this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource); if (LOGGER.isDebugEnabled()) {     LOGGER.debug("JDBC Connection [" + this.connection + "] will" + (this.isConnectionTransactional ? " " : " not ") + "be managed by Spring"); }    }

我们具体看一下DataSourceUtils.getConnection方法,里面调用了doGetConnection方法

public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException { try {     return doGetConnection(dataSource); } catch (SQLException var2) {     throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", var2); } catch (IllegalStateException var3) {     throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection: " + var3.getMessage()); }    }
public static Connection doGetConnection(DataSource dataSource) throws SQLException { Assert.notNull(dataSource, "No DataSource specified");  //从TransactionSynchronizationManager的线程变量resources里面获取connectionHolder,肯定是可以获取到的 ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource); if (conHolder == null || !conHolder.hasConnection() && !conHolder.isSynchronizedWithTransaction()) {     logger.debug("Fetching JDBC Connection from DataSource");     Connection con = fetchConnection(dataSource);     if (TransactionSynchronizationManager.isSynchronizationActive()) {  try {      ConnectionHolder holderToUse = conHolder;      if (conHolder == null) {   holderToUse = new ConnectionHolder(con);      } else {   conHolder.setConnection(con);      }      holderToUse.requested();      TransactionSynchronizationManager.registerSynchronization(new DataSourceUtils.ConnectionSynchronization(holderToUse, dataSource));      holderToUse.setSynchronizedWithTransaction(true);      if (holderToUse != conHolder) {   TransactionSynchronizationManager.bindResource(dataSource, holderToUse);      }  } catch (RuntimeException var4) {      releaseConnection(con, dataSource);      throw var4;  }     }     return con; } else {     //我们进入下面的逻辑     //获取到connectionHolder后,将connectionHolder的引用数量referenceCount加1,后续访问完数据库,会将conenctionHolder的引用数量减1     conHolder.requested();     if (!conHolder.hasConnection()) {  logger.debug("Fetching resumed JDBC Connection from DataSource");  conHolder.setConnection(fetchConnection(dataSource));     }     //返回数据库连接connection     return conHolder.getConnection(); }    }

看到了没,conHolder.getConnection(),就是从connectionHolder里面获取连接,同一个事务里面,共用connectionHolder,所以同一个事务里面,肯定是共用一个数据库连接的;

2.3 completeTransactionAfterThrowing方法

回到最开始的地方

{     TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);     result = null;     try {  result = invocation.proceedWithInvocation();     } catch (Throwable var17) {  this.completeTransactionAfterThrowing(txInfo, var17);  throw var17;     } finally {  this.cleanupTransactionInfo(txInfo);     }     this.commitTransactionAfterReturning(txInfo);     return result; }

如果调用目标方法失败报错,就会调用completeTransactionAfterThrowing方法;

该方法不是单纯的回滚,里面有个地方有点意思;

我们分析一种场景:

@Transactional    public void methodA(){ userMapper.selectById("jzcs"); try {     //methodB会报错,但是这里被try catch了,所以methodA就检查不到错误     infoService.getUserClassInfo("userId"); }catch (Exception e){     e.printStackTrace(); }    }    //methodB是infoService的方法    @Transactional    public void methodB(String userId){ infoMapper.selectUserClassInfo(userId); //这个地方肯定会报错 System.out.println(1/0);    }

如上所示,在我们的测试案例里面,如果在methodA方法中try  catch了methodB方法,如果methodB方法报错了,methodA会不会回滚呢?测试案例里面methodA和methodB是共用的一个事务;

注意:

我们肯定能判定:methodB报错,肯定会走completeTransactionAfterThrowing方法;

methodA没有检查到错误,所以会走commitTransactionAfterReturning方法;

我们带着这个问题去研究代码;

我们看一下methodB走的completeTransactionAfterThrowing方法做了些什么?

protected void completeTransactionAfterThrowing(@Nullable TransactionAspectSupport.TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.getTransactionStatus() != null) {   //transactionAttribute.rollbackOn(ex)该方法就是判断是否是抛的运行时异常,一般来说肯定是的     if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {  try {      //执行回滚,最重还是调用的connection.rollback()方法      txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());  } catch (TransactionSystemException var6) {      this.logger.error("Application exception overridden by rollback exception", ex);      var6.initApplicationException(ex);      throw var6;  } catch (Error | RuntimeException var7) {      this.logger.error("Application exception overridden by rollback exception", ex);      throw var7;  }     } else {  //省略部分没有用到的代码     } }    }

调用AbstractPlatformTransactionManager的rollback方法

public final void rollback(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"); } else { //调用processRollback方法     DefaultTransactionStatus defStatus = (DefaultTransactionStatus)status;     this.processRollback(defStatus, false); }    }

进入到AbstractPlatformTransactionManager的processRollback方法

private void processRollback(DefaultTransactionStatus status, boolean unexpected) { try {     boolean unexpectedRollback = unexpected;     try {  this.triggerBeforeCompletion(status);  if (status.hasSavepoint()) {      if (status.isDebug()) {   this.logger.debug("Rolling back transaction to savepoint");      }      status.rollbackToHeldSavepoint();  //如果是第一个方法内部执行报错,它的isNewTransaction为true,就会直接执行doRollback回滚  } else if (status.isNewTransaction()) {      if (status.isDebug()) {   this.logger.debug("Initiating transaction rollback");      }      this.doRollback(status);  } else {      //但是如果是上面说的,是methodB报错,这个是和methodA共用的一个事务,它就会走下面的代码      if (status.hasTransaction()) {   //!isGlobalRollbackOnParticipationFailure为false,!status.isLocalRollbackOnly()为true   if (!status.isLocalRollbackOnly() && !this.isGlobalRollbackOnParticipationFailure()) {//省略部分代码   } else {//上面说的场景就会走这步if (status.isDebug()) {    this.logger.debug("Participating transaction failed - marking existing transaction as rollback-only");}//就会执行这个方法,我们详细看一下该代码this.doSetRollbackOnly(status);   }      } else {   this.logger.debug("Should roll back transaction but cannot - no transaction available");      }      if (!this.isFailEarlyOnGlobalRollbackOnly()) {   unexpectedRollback = false;      }  }     } catch (Error | RuntimeException var8) {  this.triggerAfterCompletion(status, 2);  throw var8;     }     this.triggerAfterCompletion(status, 1);     if (unexpectedRollback) {  throw new UnexpectedRollbackException("Transaction rolled back because it has been marked as rollback-only");     } } finally {     this.cleanupAfterCompletion(status); }

我们详细看一下AbstractPlatformTransactionManager的doSetRollbackOnly这个方法

protected void doSetRollbackOnly(DefaultTransactionStatus status) { DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction(); if (status.isDebug()) {     this.logger.debug("Setting JDBC transaction [" + txObject.getConnectionHolder().getConnection() + "] rollback-only"); } //调用setRollbackOnly方法,我们去看一下具体代码做了什么 txObject.setRollbackOnly();    }

调用DataSourceTransactionManager.DataSourceTransactionObject的setRollbackOnly方法

 public void setRollbackOnly() {     this.getConnectionHolder().setRollbackOnly(); }

看到没有,是调用的connectionHolder的setRollbackOnly()方法,connectionHolder这个类大家还记得吗,就是保存到TransactionSynchronizationManager的线程变量resources里面的;里面包含了数据库连接信息;

我们看一下这个方法干了些什么?

public void setRollbackOnly() { this.rollbackOnly = true;    }

再次先提醒:methoA和methodB共用的一个事务,也就共用的一个connectionHolder哦;

设置connectionHolder的rollbackOnly属性为true;这个标识很重要的,因为methodA的内部,try catch 了methodB方法,如果methodB方法报错了,methodB就会在执行completeTransactionAfterThrowing方法的时候,实际是调用了上面分析的方法,将connectionHolder的rollbackOnly属性设置为true;

好methodB就执行完了,接下来我们看看methodA走的commitTransactionAfterReturning方法;

2.4 commitTransactionAfterReturning方法

如果调用目标方法没有报错,就会调用该方法

protected void commitTransactionAfterReturning(@Nullable TransactionAspectSupport.TransactionInfo txInfo) { if (txInfo != null && txInfo.getTransactionStatus() != null) {     if (this.logger.isTraceEnabled()) {  this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");     }     //调用commit方法     txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); }    }

进入AbstractPlatformTransactionManager的commit方法

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"); } else {     //我们进入到这里     DefaultTransactionStatus defStatus = (DefaultTransactionStatus)status;   //isLocalRollbackOnly为false     if (defStatus.isLocalRollbackOnly()) {  if (defStatus.isDebug()) {      this.logger.debug("Transactional code has requested rollback");  }  this.processRollback(defStatus, false);     //我们进入到下面方法,!this.shouldCommitOnGlobalRollbackOnly为true,重点是defStatus.isGlobalRollbackOnly()这个方法,我们下面详细看一下这个方法     } else if (!this.shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {  if (defStatus.isDebug()) {      this.logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");  }  this.processRollback(defStatus, true);     } else {  this.processCommit(defStatus);     } }    }

我们进入到isGlobalRollbackOnly方法:

public boolean isGlobalRollbackOnly() {  //主要是((SmartTransactionObject)this.transaction).isRollbackOnly()这个判断,我们再进入到这个方法 return this.transaction instanceof SmartTransactionObject && ((SmartTransactionObject)this.transaction).isRollbackOnly();    }

再进入到isRollbackOnly()方法:

 public boolean isRollbackOnly() {     //重点戏来了,获取connectionHolder中的rollbackOnly属性     return this.getConnectionHolder().isRollbackOnly(); }

重点来了:isRollbackOnly()方法,是获取到connectionHolder的rollbackOnly属性,判断是否为true;我们上面的案例里面,methodB报错后,进入到completeTransactionAfterThrowing方法里面,将共用的connectionHolder设置为了true,所以,methodA进入到commitTransactionAfterReturning方法里面发现connectionHolder为true,就会调用processRollback方法执行回滚了;

并且会报错,如下

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

所以,methodA和methodB都会回滚;

当然,如果methodB不报错,肯定就会正常提交啦;

总结:

上面我们介绍了@Transactional注解的源码:

1.TransactionInterceptor负责拦截加了@Transactional注解的方法;

2.TransactionAspectSupport负责对目标方法增强

        2.1 在目标方法前创建事务和数据库连接;

        2.2 在目标方法报错后执行回滚或者加回滚标识(设置connectionHolder的rollbackOnly为true)

        2.3 在目标方法执行成功后执行提交或者回滚(如果检查到connectionHolder的rollbackOnly为true,就会执行回滚,不然就执行提交)