今天下午突然脑袋灵光一闪,就想到了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都和线程进行绑定的。