spring + mybtis 事务详解(connection一致性)

一、spring IOC容器会为添加了@Transaction注解的方法进行事务增强(动态代理)

spring + mybtis 事务详解(connection一致性)_第1张图片

在调用方法之前会调用TransactionInterceptor的invoke方法:

spring + mybtis 事务详解(connection一致性)_第2张图片

又会调用到父类TransactionAspectSupport的invokeWithinTransaction方法,主要关注createTransactionIfNecessary

spring + mybtis 事务详解(connection一致性)_第3张图片

进入该方法会调用PlatformTransactionManager#getTransaction方法获取TransactionStatus:

spring + mybtis 事务详解(connection一致性)_第4张图片

二、Connection绑定

PlatformTransactionManager是spring事务的高级抽象,事务的实现需要借助PlatformTransactionManager完成,接下来就看一下AbstractPlatformTransactionManager#getTransaction源码:

  @Override
    public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
        
        //transaction类型:DataSourceTransactionManager.DataSourceTransactionObject
        //注意 DataSourceTransactionObject的数据结构,DataSourceTransactionObject包含一个ConnectionHolder
        // 此时会
        Object transaction = doGetTransaction();
 
        if (definition == null) {
            // 如果传入的事务定义实例为null的话则创建一个默认的事务定义实例
            definition = new DefaultTransactionDefinition();
        }
 
        if (isExistingTransaction(transaction)) {
            // 事务传播行为有关的的处理
            return handleExistingTransaction(definition, transaction, debugEnabled);
        }
 
        // Check definition settings for new transaction.
        if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
            throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
        }
 
        // No existing transaction found -> check propagation behavior to find out how to proceed.
        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);
                DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
                //重重之重的代码,完成创建数据库连接绑定以及设置自动提交为False以及
                doBegin(transaction, definition);
                prepareSynchronization(status, definition);
                return status;
            } catch (RuntimeException ex) {
                resume(null, suspendedResources);
                throw ex;
            } catch (Error err) {
                resume(null, suspendedResources);
                throw err;
            }
        } 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);
        }
    }
doGetTransaction方法会尝试获取连接,如果当前线程没有绑定Connection的话则返回null,org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction源码如下:
	@Override
	protected Object doGetTransaction() {
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		// 重点代码,使用TransactionSynchronizationManager获取上下文是否有Connection
        //TransactionSynchronizationManager获取连接是借助ThreadLocal实现的
        ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
	}

在doGetTransaction如果当前没有绑定连接的话,则需要给当前线程绑定一个连接;org.springframework.transaction.support.AbstractPlatformTransactionManager#doBegin方法是事务的基础,接下里以DataSourceTransactionManager实现为例,查看一下源码:

@Override
    protected void doBegin(Object transaction, TransactionDefinition definition) {
        // DataSourceTransactionObject持有数据库连接ConnectionHolder成员
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        Connection con = null;
 
        try {
            if (txObject.getConnectionHolder() == null ||txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                // 上下文没有获取到Connection,因此需要在数据库连接池中获取一个Connection 并设置到事务对象中
                // 但是由于该连接并没有和线程绑定因此需要跟线程绑定,下文TransactionSynchronizationManager.bindResourc方法绑定到线程
                Connection newCon = this.dataSource.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);
            
            if (con.getAutoCommit()) {
                txObject.setMustRestoreAutoCommit(true);
                if (logger.isDebugEnabled()) {
                    logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                }
                con.setAutoCommit(false);
            }
            txObject.getConnectionHolder().setTransactionActive(true);
 
            int timeout = determineTimeout(definition);
            if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
                txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
            }
 
            // 将连接跟当前线程进行绑定
            if (txObject.isNewConnectionHolder()) {
                TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
            }
        } catch (Throwable ex) {
            if (txObject.isNewConnectionHolder()) {
                DataSourceUtils.releaseConnection(con, this.dataSource);
                txObject.setConnectionHolder(null, false);
            }
            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
        }
    }

到此为止就完成了当前线程的Connection绑定,主要关注TransactionSynchronizationManager#bindResource方法,传入两个参数:分别是DataSource与ConnechtionHolder,这是为了避免一个线程处理多个连接池的Connection时候出错而设置,这样获取连接时候会根据线程与连接池共同为key获取对应的唯一Connection。在Connection绑定时TransactionSynchronizationManager是一个重要的工具。

三、Mapper调用(动态代理)

最终会调用SqlSessionTemplate.sqlSessionProxy相应方法,由于sqlSessionProxy也是代理对象:

spring + mybtis 事务详解(connection一致性)_第5张图片

最终会调用SqlSessionInterceptor#invoke方法:

spring + mybtis 事务详解(connection一致性)_第6张图片

会调用SqlSessionUtils#getSqlSession方法获取SqlSession:

spring + mybtis 事务详解(connection一致性)_第7张图片

从源代码中知道真正的SqlSessionFactory使用的是org.apache.ibatis.session.defaults.DefaultSqlSessionFactory的实例,同时,事务管理使用org.mybatis.spring.transaction.SpringManagedTransactionFactory

重点关注Executor,SqlSession会通过Executor调用数据库,而Executor会通过SpringManagedTransaction#openConnection获取数据库连接

spring + mybtis 事务详解(connection一致性)_第8张图片

 

 

此处以查询举例,会调用Executor#doQuery方法:

spring + mybtis 事务详解(connection一致性)_第9张图片

最终会调用DataSourceUtils#doGetConnection获取

真正的数据库连接,其中TransactionSynchronizationManager中保存的就是方法调用前,spring增强方法中绑定到线程的connection,从而保证整个事务过程中connection的一致性

spring + mybtis 事务详解(connection一致性)_第10张图片

spring + mybtis 事务详解(connection一致性)_第11张图片

你可能感兴趣的:(Transaction,spring,mybatis,Transaction,connection一致性)