MyBatis整合Spring怎么使用connnection

  今天下午突然脑袋灵光一闪,就想到了mybatis在整合了spring后,在web环境下多线程的时候是怎么使用connnection的呢?

  于是我翻出了源码

DefaultSqlSessionFactory
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  我们知道,mybatis本身调用getMapper方法会对mapper进行动态代理

<mapper namespace="com.suning.rdrs.admin.dao.RdrsAdminMapper">

  我们都会在项目中写一个接口  com.suning.rdrs.admin.dao.RdrsAdminMapper,该接口就会被动态代理。

  spring在整合mybatis的时候其实就是把动态代理的mapper都封装成了bean,我们才能在service的实现类里@Autowired

  sqlsession.getMapper的逻辑不是本次要讨论的重点,它本身的逻辑也不复杂

  本文的重点是看看如何得到connectioin

  Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);//实际是SpringManagedTransactionFactory
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);//SpringManagedTransaction

 这样executor里面就有了 SpringManagedTransaction

protected BaseExecutor(Configuration configuration, Transaction transaction) {
    this.transaction = transaction;
    this.deferredLoads = new ConcurrentLinkedQueue<DeferredLoad>();
    this.localCache = new PerpetualCache("LocalCache");
    this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
    this.closed = false;
    this.configuration = configuration;
    this.wrapper = this;
  }

  我们以SimpleExecutor的一个方法为例

@Override
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.update(stmt);
    } finally {
      closeStatement(stmt);
    }
  }
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
    Statement stmt;
    Connection connection = getConnection(statementLog);
    stmt = handler.prepare(connection);
    handler.parameterize(stmt);
    return stmt;
  }
protected Connection getConnection(Log statementLog) throws SQLException {
    Connection connection = transaction.getConnection();
    if (statementLog.isDebugEnabled()) {
      return ConnectionLogger.newInstance(connection, statementLog, queryStack);
    } else {
      return connection;
    }
  }

下面就是spring里面的操作了

private void openConnection() throws SQLException {
    this.connection = DataSourceUtils.getConnection(this.dataSource);
    this.autoCommit = this.connection.getAutoCommit();
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
        Assert.notNull(dataSource, "No DataSource specified");

        ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);

不陌生吧,分析spring事务的时候都建过的,就是ThreadLocal的实际应用

  总结

  在spring初始化的时候,就已经初始化了每一个mapper的代理类,并把这些代理类做成了bean。

  SqlSession在一开始就确定了,executor,同时executor也确定了  SpringManagedTransaction,但是这些都不用担心。

  每次executor在执行一个方法的时候,都会执行一次 prepareStatement,在 prepareStatement里进行connection的获取,这里就能够看出来了每个connection都和线程进行绑定的。

  

原文地址:https://www.cnblogs.com/juniorMa/p/13921627.html