spring事务源码阅读及mybatis整合问题探索 笔记

148 阅读9分钟

1、准备工作

orm框架使用mybatis,以xml方式启动spring

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd">
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
       <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
       <property name="url" value="jdbc:mysql://localhost/test" />
       <property name="username" value="root" />
       <property name="password" value="12345" />
    </bean>
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
       <property name="dataSource" ref="dataSource" />
       <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
       <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/>
       <property name="basePackage" value="org.spring.dao"/>
    </bean>
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource" />
    </bean>
    <bean id="equipServiceImpl" class="org.spring.serviceImpl.EquipServiceImpl">
       <property name="equipMapper" ref="equipMapper"/>
       <property name="platformTransactionManager" ref="dataSourceTransactionManager"/>
    </bean>
</beans>

测试代码,编程式事务

public class EquipServiceImpl {

    private EquipMapper equipMapper;

    private PlatformTransactionManager platformTransactionManager;

    public void a(){
       TransactionStatus transaction = platformTransactionManager.getTransaction(new DefaultTransactionDefinition());
       System.out.println(equipMapper.updateOne());
       int a = 1/0;
       System.out.println(equipMapper.updateTwo());
       platformTransactionManager.commit(transaction);
    }
}

2、流程分析

DefaultTransactionDefinition默认的spring事务定义,实现TransactionDefinition接口,用于spring事务的定义,可根据业务需要自主实现TransactionDefinition接口

public interface TransactionDefinition {

    /**
     * 如果当前没有事务,则自己新建一个事务,如果当前存在事务则加入这个事务
     */
    int PROPAGATION_REQUIRED = 0;

    /**
     * 当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
     */
    int PROPAGATION_SUPPORTS = 1;

    /**
     * 当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常
     */
    int PROPAGATION_MANDATORY = 2;

    /**
     * 创建一个新事务,如果存在当前事务,则挂起该事务
     */
    int PROPAGATION_REQUIRES_NEW = 3;

    /**
     * 以非事务方式执行,如果当前存在事务,则挂起当前事务
     * 被调用者B会以非事务方式运行(直接提交),如果当前有事务,也就是A中有事务,A会被挂起(不执行,等待B执行完,返回);A和B出现异常需要回滚,互不影响
     */
    int PROPAGATION_NOT_SUPPORTED = 4;

    /**
     * 如果当前没有事务存在,就以非事务方式执行;如果有,就抛出异常。就是B从不以事务方式运行
     */
    int PROPAGATION_NEVER = 5;

    /**
     * 如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样(开启一个事务)
     */
    int PROPAGATION_NESTED = 6;


    int ISOLATION_DEFAULT = -1;

    /**
     * 读未提交
     */
    int ISOLATION_READ_UNCOMMITTED = 1;  // same as java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;

    /**
     * 读已提交
     */
    int ISOLATION_READ_COMMITTED = 2;  // same as java.sql.Connection.TRANSACTION_READ_COMMITTED;

    /**
     * 可重复读
     */
    int ISOLATION_REPEATABLE_READ = 4;  // same as java.sql.Connection.TRANSACTION_REPEATABLE_READ;

    /**
     * 串行化
     */
    int ISOLATION_SERIALIZABLE = 8;  // same as java.sql.Connection.TRANSACTION_SERIALIZABLE;

    /**
     * 事务超时时间
     */
    int TIMEOUT_DEFAULT = -1;

    /**
     * 默认是PROPAGATION_REQUIRED传播行为
     */
    default int getPropagationBehavior() {
       return PROPAGATION_REQUIRED;
    }

    /**
     * 隔离级别是定义在数据库的,个人认为此处只是为了标识
     */
    default int getIsolationLevel() {
       return ISOLATION_DEFAULT;
    }
    
    default int getTimeout() {
       return TIMEOUT_DEFAULT;
    }

    default boolean isReadOnly() {
       return false;
    }
   
    @Nullable
    default String getName() {
       return null;
    }

    static TransactionDefinition withDefaults() {
       return StaticTransactionDefinition.INSTANCE;
    }

}

1、getTransaction方法

首先判断当前是否存在事务,进一步根据定义的事务传播行为进行不同的逻辑

@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
       throws TransactionException {

    // 是否使用默认的事务定义
    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
       // 返回一个新的DataSourceTransactionObject,当前线程是否有连接
    Object transaction = doGetTransaction();
    boolean debugEnabled = logger.isDebugEnabled();
       // 是否有连接,并且连接存活
    if (isExistingTransaction(transaction)) {
       // 当前存在事务
       return handleExistingTransaction(def, transaction, debugEnabled);
    }

    // Check definition settings for new transaction.
    if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
       throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
    }

    // 当前不存在事务,判断传播级别是否是PROPAGATION_MANDATORY,是抛异常
    if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
       throw new IllegalTransactionStateException(
             "No existing transaction found for transaction marked with propagation 'mandatory'");
    }
    else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
          def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
          def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
       // 当前不存在事务,开启一个新的事务
       // 挂起给定的事务
       SuspendedResourcesHolder suspendedResources = suspend(null);
       if (debugEnabled) {
          logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
       }
       try {
          return startTransaction(def, transaction, debugEnabled, suspendedResources);
       }
       catch (RuntimeException | Error ex) {
          resume(null, suspendedResources);
          throw ex;
       }
    }
    else {
       // 说明当前事务传播行为是非事务
       // Create "empty" transaction: no actual transaction, but potentially synchronization.
       if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
          logger.warn("Custom isolation level specified but no actual transaction initiated; " +
                "isolation level will effectively be ignored: " + def);
       }
       boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
       return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
    }
}

问题:如何判断当前是否存在事务

该方法判断了transcationObject存在ConnectionHolder并且ConnectionHolder事务存活为存在事务

@Override
protected boolean isExistingTransaction(Object transaction) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}

ConnectionHolder中重要属性

public class ConnectionHolder extends ResourceHolderSupport {

    /**
     * Prefix for savepoint names.
     */
    public static final String SAVEPOINT_NAME_PREFIX = "SAVEPOINT_";


    @Nullable
    // 数据库连接
    private ConnectionHandle connectionHandle;

    @Nullable
    // 当前数据库连接
    private Connection currentConnection;
    
    // 事务状态是否存活
    private boolean transactionActive = false;

    @Nullable
    // 是否支持保存点 默认不支持
    private Boolean savepointsSupported;
    
    // 保存点计数器
    private int savepointCounter = 0;
    
    ***基本可以认定ConnectionHolder对象就是对数据库连接Connection的进一步封装***

进一步查找ConnectionHolder的设置来源

@Override
protected Object doGetTransaction() {
    DataSourceTransactionObject txObject = new DataSourceTransactionObject();
    txObject.setSavepointAllowed(isNestedTransactionAllowed());
    ConnectionHolder conHolder =
          (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
    txObject.setConnectionHolder(conHolder, false);
    return txObject;
}

// 事务同步管理器 threadLocal 当前线程
public abstract class TransactionSynchronizationManager {
    // 存储当前线程的连接,key是数据源对象,value是封装后的连接对象
    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");

ConnectionHolder从事务同步管理器的threadLoad中获取,也就是当前线程

2、handleExistingTransaction 当前已存在事务

image.png

private TransactionStatus handleExistingTransaction(
       TransactionDefinition definition, Object transaction, boolean debugEnabled)
       throws TransactionException {
       // 当前存在事务,传播行为为PROPAGATION_NEVER直接抛出异常
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
       throw new IllegalTransactionStateException(
             "Existing transaction found for transaction marked with propagation 'never'");
    }
       // 挂起当前事务,以非事务的方式运行
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
       if (debugEnabled) {
          logger.debug("Suspending current transaction");
       }
       // 挂起给定的事务
       Object suspendedResources = suspend(transaction);
       boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
       return prepareTransactionStatus(
             definition, null, false, newSynchronization, debugEnabled, suspendedResources);
    }
       // 挂起当前事务,创建新的事物
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
       if (debugEnabled) {
          logger.debug("Suspending current transaction, creating new transaction with name [" +
                definition.getName() + "]");
       }
       // 挂起当前事务
       SuspendedResourcesHolder suspendedResources = suspend(transaction);
       try {
          // 开启新的事务
          return startTransaction(definition, transaction, debugEnabled, suspendedResources);
       }
       catch (RuntimeException | Error beginEx) {
          resumeAfterBeginException(transaction, suspendedResources, beginEx);
          throw beginEx;
       }
    }
       // 嵌套事务
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
       if (!isNestedTransactionAllowed()) {
          throw new NestedTransactionNotSupportedException(
                "Transaction manager does not allow nested transactions by default - " +
                "specify 'nestedTransactionAllowed' property with value 'true'");
       }
       if (debugEnabled) {
          logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
       }
       if (useSavepointForNestedTransaction()) {
          // Create savepoint within existing Spring-managed transaction,
          // through the SavepointManager API implemented by TransactionStatus.
          // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
          DefaultTransactionStatus status =
                prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
          status.createAndHoldSavepoint();
          return status;
       }
       else {
          // Nested transaction through nested begin and commit/rollback calls.
          // Usually only for JTA: Spring synchronization might get activated here
          // in case of a pre-existing JTA transaction.
          return startTransaction(definition, transaction, debugEnabled, null);
       }
    }
    // PROPAGATION_REQUIRED  PROPAGATION_SUPPORTS 加入当前事务
    if (debugEnabled) {
       logger.debug("Participating in existing transaction");
    }
    // 默认关闭验证 验证当前事务的隔离级别是否与新的事务隔离级别一致  当前事务是否只读和新的事务是否一致
    if (isValidateExistingTransaction()) {
       if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
          Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
          if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
             Constants isoConstants = DefaultTransactionDefinition.constants;
             throw new IllegalTransactionStateException("Participating transaction with definition [" +
                   definition + "] specifies isolation level which is incompatible with existing transaction: " +
                   (currentIsolationLevel != null ?
                         isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
                         "(unknown)"));
          }
       }

       if (!definition.isReadOnly()) {
          if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
             throw new IllegalTransactionStateException("Participating transaction with definition [" +
                   definition + "] is not marked as read-only but existing transaction is");
          }
       }
    }
    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}

事务挂起方法

protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
    // 当前线程事务状态是否是存活,也是查自threadlocal
    if (TransactionSynchronizationManager.isSynchronizationActive()) {
       // 事务全部挂起
       List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
       try {
          Object suspendedResources = null;
          if (transaction != null) {
             // 指定的事务的连接从threadLocal中解绑
             suspendedResources = doSuspend(transaction);
          }
          String name = TransactionSynchronizationManager.getCurrentTransactionName();
          TransactionSynchronizationManager.setCurrentTransactionName(null);
          boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
          TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
          Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
          TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
          boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
          TransactionSynchronizationManager.setActualTransactionActive(false);
          // 保存挂起的事务和全部的事务
          return new SuspendedResourcesHolder(
                suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
       }
       catch (RuntimeException | Error ex) {
          // doSuspend failed - original transaction is still active...
          doResumeSynchronization(suspendedSynchronizations);
          throw ex;
       }
    }
    else if (transaction != null) {
       // Transaction active but no synchronization active.
       // 给定事务存活但是没有同步
       Object suspendedResources = doSuspend(transaction);
       return new SuspendedResourcesHolder(suspendedResources);
    }
    else {
       // Neither transaction nor synchronization active.
       return null;
    }
}

3、开启新事务

private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
       boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

    boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
    // 将已挂起的事务保存到新的事务对象中
    DefaultTransactionStatus status = newTransactionStatus(
          definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
    doBegin(transaction, definition);
    prepareSynchronization(status, definition);
    return status;
}

// 开启事务
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);
       }
       // 数据库连接与事务同步设置为true
       txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
       con = txObject.getConnectionHolder().getConnection();
       // 判断事务定义与数据库连接的设置是否一致
       Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
       txObject.setPreviousIsolationLevel(previousIsolationLevel);
       txObject.setReadOnly(definition.isReadOnly());
       // 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);
       }
       // 绑定数据库连接与当前线程
       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);
    }

4、commit方法

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
    try {
       boolean beforeCompletionInvoked = false;
       try {
          boolean unexpectedRollback = false;
          prepareForCommit(status);
          triggerBeforeCommit(status);
          // 连接与当前数据库解绑,并且释放连接,当前事务不需要提交
          triggerBeforeCompletion(status);
          beforeCompletionInvoked = true;
          // 嵌套事务使用
          if (status.hasSavepoint()) {
             if (status.isDebug()) {
                logger.debug("Releasing transaction savepoint");
             }
             unexpectedRollback = status.isGlobalRollbackOnly();
             status.releaseHeldSavepoint();
          }
          // 当前事务是否需要提交,如果事务传播行为是 PROPAGATION_NOT_SUPPORTED,则是不需要提交的
          else if (status.isNewTransaction()) {
             if (status.isDebug()) {
                logger.debug("Initiating transaction commit");
             }
             unexpectedRollback = status.isGlobalRollbackOnly();
             // 提交事务
             doCommit(status);
          }
          else if (isFailEarlyOnGlobalRollbackOnly()) {
             unexpectedRollback = status.isGlobalRollbackOnly();
          }

          if (unexpectedRollback) {
             throw new UnexpectedRollbackException(
                   "Transaction silently rolled back because it has been marked as rollback-only");
          }
       }
       catch (UnexpectedRollbackException ex) {
          // can only be caused by doCommit
          triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
          throw ex;
       }
       catch (TransactionException ex) {
          // can only be caused by doCommit
          if (isRollbackOnCommitFailure()) {
             doRollbackOnCommitException(status, ex);
          }
          else {
             triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
          }
          throw ex;
       }
       catch (RuntimeException | Error ex) {
          if (!beforeCompletionInvoked) {
             triggerBeforeCompletion(status);
          }
          doRollbackOnCommitException(status, ex);
          throw ex;
       }
       try {
          triggerAfterCommit(status);
       }
       finally {
          triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
       }

    }
    finally {
       // 事务提交后的处理 1、数据连接设置为初始化状态 如autocommit 2、挂起的事务重新开启
       cleanupAfterCompletion(status);
    }
}

rollback事务回滚方法与commit方法类似

总结

  • AbstractPlatformTransactionManager抽象类.getTransaction核心创建事务的方法,可以使用不同的事务管理器继承AbstractPlatformTransactionManager抽象类重写相关细节方法(门面模式),首先判断当前是否存在事务,判断当前线程是否绑定了数据库连接
  • 当前是否存在事务,再根据不同的事务传播行为进行不同的逻辑处理
  • getTransaction返回TransactionStatus事务对象,保存当前事务状态、数据库连接、与挂起的事务等信息
  • commit和rollback调用数据库Connection对象进行事务的提交或回滚

3、问题探索

问题:我们知道,在spring与mybatis整合后,mapper执行sql首先获取sqlsession,mybatis的sqlsession是线程级别,sqlsession通过Excutor执行器Transaction.getConnection获取数据库连接对象执行sql,那么在spring中事务开启后,spring是如何保证同一事务下mybatis执行sql使用的是spring事务创建的连接呢?

mybatis获取数据库连接执行sql是在Executor中进行的

protected Connection getConnection(Log statementLog) throws SQLException {
  Connection connection = transaction.getConnection();
  if (statementLog.isDebugEnabled()) {
    return ConnectionLogger.newInstance(connection, statementLog, queryStack);
  } else {
    return connection;
  }
}
这里的transaction是mybatis的transaction,整合spring后默认实现类为SpringManagedTransaction,在整合之后事务就已经全交给spring管理了

SpringManagedTransaction
@Override
public Connection getConnection() throws SQLException {
  if (this.connection == null) {
    openConnection();
  }
  return this.connection;
}

SpringManagedTransaction
private void openConnection() throws SQLException {
  this.connection = DataSourceUtils.getConnection(this.dataSource);
  this.autoCommit = this.connection.getAutoCommit();
  this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);

  LOGGER.debug(() -> "JDBC Connection [" + this.connection + "] will"
      + (this.isConnectionTransactional ? " " : " not ") + "be managed by Spring");
}

DataSourceUtils
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
    Assert.notNull(dataSource, "No DataSource specified");
    // 获取当前线程绑定的连接对象
    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
    if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
       conHolder.requested();
       if (!conHolder.hasConnection()) {
          logger.debug("Fetching resumed JDBC Connection from DataSource");
          conHolder.setConnection(fetchConnection(dataSource));
       }
       return conHolder.getConnection();
    }
    // Else we either got no holder or an empty thread-bound holder here.

    logger.debug("Fetching JDBC Connection from DataSource");
    Connection con = fetchConnection(dataSource);

    if (TransactionSynchronizationManager.isSynchronizationActive()) {
       try {
          // Use same Connection for further JDBC actions within the transaction.
          // Thread-bound object will get removed by synchronization at transaction completion.
          ConnectionHolder holderToUse = conHolder;
          if (holderToUse == null) {
             holderToUse = new ConnectionHolder(con);
          }
          else {
             holderToUse.setConnection(con);
          }
          holderToUse.requested();
          TransactionSynchronizationManager.registerSynchronization(
                new ConnectionSynchronization(holderToUse, dataSource));
          holderToUse.setSynchronizedWithTransaction(true);
          if (holderToUse != conHolder) {
             TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
          }
       }
       catch (RuntimeException ex) {
          // Unexpected exception from external delegation call -> close Connection and rethrow.
          releaseConnection(con, dataSource);
          throw ex;
       }
    }

    return con;
}

当spring开启事务后,mybatis执行sql获取连接首先从spring的事务同步管理器获取,也就是spring开启事务时绑定当前线程的连接

mybatis中,每当有新线程要执行sql创建sqlsession时,都会为这个sqlsession的Excutor创建一个新的SpringManagedTransaction,而Excutor第一次执行sql从数据库连接池获取数据库连接后,会把这个数据库连接保存在SpringManagedTransaction的属性中,下次再执行sql直接从SpringManagedTransaction的属性中获取;即线程级sqlsession对应各自的connection