spring与mybatis的conneciton对象原理

首先配置sqlsessionFactoryBean

  1. 首先配置一个sqlSessionFactoryBean,创建的时候会自动生成一个configuration,会把数据库信息赋值给environment里面在dao层取值的时候,会根据这个值取datasource的值,datasource作为key取连接对象
 public void afterPropertiesSet() throws Exception {
       Assert.notNull(this.dataSource, "Property 'dataSource' is required");
       Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
       Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
       this.sqlSessionFactory = this.buildSqlSessionFactory();
   }
    targetConfiguration.setEnvironment(new Environment(this.environment, (TransactionFactory)(this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory), this.dataSource));
  
  1. 生成了SpringManagedTransactionFactory
    SpringManagedTransactionFactory来生成springManagedTransaction类
 public Connection getConnection() throws SQLException {
        if (this.connection == null) {
            this.openConnection();
        }
        return this.connection;
    }
 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(() -> {
            return "JDBC Connection [" + this.connection + "] will" + (this.isConnectionTransactional ? " " : " not ") + "be managed by Spring";
        });
    }

如果事物里面没有开启,DataSourceUtils.getConnection拿到的是一个新的连接,否则是一个前面放置的事物连接

事物的Connection对象的绑定到线程的时机

核心code:TransactionSynchronizationManager.bindResource(this.getDataSource(), txObject.getConnectionHolder());
我们注意到ConnectionHolder进行了存储,存储的key是获取的dataSource(),此时的dataSource为我们注入的热库datasource。




接下来我们获取事务,我们通过数据源得到一个ConnectionHolder保存在事务管理器中,获取ConnectionHolder,是通过
DataSourceTransactionManager.get
TransactionSynchronizationManager.getResource获取,这个方法非常重要。


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


TransactionSynchronizationManager
  @Nullable
    public static Object getResource(Object key) {
        Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
        Object value = doGetResource(actualKey);
        if (value != null && logger.isTraceEnabled()) {
            logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
        }
        return value;
    }

TransactionSynchronizationManager
  @Nullable
    private static Object doGetResource(Object actualKey) {
        Map<Object, Object> map = (Map)resources.get();
        if (map == null) {
            return null;
        } else {
            Object value = map.get(actualKey);
            if (value instanceof ResourceHolder && ((ResourceHolder)value).isVoid()) {
                map.remove(actualKey);
                if (map.isEmpty()) {
                    resources.remove();
                }
                value = null;
            }
            return value;
        }
    }
    
我们看方法都可以猜到,第一次获取链接肯定不存在的,毕竟我们还没有进行存储。
接下来操作肯定是要得到一个连接,从哪里得到,
当然是通过我们注入的dataSource得到链接

首先我们看事务管理器获取Connection,在DataSourceTransactionManager#doGetTransaction中首先获取ConnectionHolder放置在DataSourceTransactionManager.DataSourceTransactionObject中,我们注意到是从TransactionSynchronizationManager.getResource(this.dataSource)通过我们注入的数据源获取holder


别的文档拷贝的
我们看看PlatformTransactionManager子类AbstractPlatformTransactionManager对该方法的实现,这个方法其实不陌生,在《Spring事物03-源码分析TransactionInterceptor》中我们分析的,拦截器的invoke方法最后就是调用这个方法来开启事物,里面会处理传播属性的各种情况。这里只看获取TransactionStatus,实际上获取的是DefaultTransactionStatus实例,这里面首先会获取Object transaction ,然后构造DefaultTransactionStatus对象返回。

拦截器的入口处

拦截器里面调用事物的地方


	AbstractPlatformTransactionManager
	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
	     Object transaction = doGetTransaction();
        //省略...
	    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) {
        DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)transaction;
        Connection con = null;

        try {
            if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                Connection newCon = this.obtainDataSource().getConnection();
                if (this.logger.isDebugEnabled()) {
                    this.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);
            txObject.setReadOnly(definition.isReadOnly());
            if (con.getAutoCommit()) {
                txObject.setMustRestoreAutoCommit(true);
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                }

                con.setAutoCommit(false);
            }

            this.prepareTransactionalConnection(con, definition);
            txObject.getConnectionHolder().setTransactionActive(true);
            int timeout = this.determineTimeout(definition);
            if (timeout != -1) {
                txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
            }

            if (txObject.isNewConnectionHolder()) {
                TransactionSynchronizationManager.bindResource(this.obtainDataSource(), txObject.getConnectionHolder());
            }

        } catch (Throwable var7) {
            if (txObject.isNewConnectionHolder()) {
                DataSourceUtils.releaseConnection(con, this.obtainDataSource());
                txObject.setConnectionHolder((ConnectionHolder)null, false);
            }
            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", var7);
        }
    }



  public static void bindResource(Object key, Object value) throws IllegalStateException {
        Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
        Assert.notNull(value, "Value must not be null");
        Map<Object, Object> map = (Map)resources.get();
        if (map == null) {
            map = new HashMap();
            resources.set(map);
        }

        Object oldValue = ((Map)map).put(actualKey, value);
        if (oldValue instanceof ResourceHolder && ((ResourceHolder)oldValue).isVoid()) {
            oldValue = null;
        }

        if (oldValue != null) {
            throw new IllegalStateException("Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
        } else {
            if (logger.isTraceEnabled()) {
                logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" + Thread.currentThread().getName() + "]");
            }

        }
    }

获取数据源

接下来我们获取事务,我们通过数据源得到一个ConnectionHolder保存在事务管理器中,获取ConnectionHolder,是通过TransactionSynchronizationManager.getResource获取,这个方法非常重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值