mybatis--MapperProxy事务
上篇 详细分析了org.mybatis.spring.mapper.MapperScannerConfigurer 和 org.mybatis.spring.SqlSessionFactoryBean的作用,可以直接看最后的总结
MapperFactoryBean是mapper接口的入口,它包含了sqlSessionFactory的封装SqlSessionTemplate,而sqlSessionFactory又包含了mapper xml的组装Configuration对象
从SqlSessionTemplate的
public <T> T getMapper(Class<T> type) {
return this.getConfiguration().getMapper(type, this);
}
开始,进入Configuration的getMapper(type,sqlsession)
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
进入MapperRegistry
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if(mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
由MapperProxyFactory生成代理MapperProxy
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
MapperProxy mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
所以最终的调用会进入MapperProxy,接下来几步在 mybatis缓存 中有介绍,会调用sqlSession(实际是SqlSessionTemplate)中的方法,看构造方法:
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { Assert.notNull(sqlSessionFactory, "Property \'sqlSessionFactory\' is required"); Assert.notNull(executorType, "Property \'executorType\' is required"); this.sqlSessionFactory = sqlSessionFactory; this.executorType = executorType; this.exceptionTranslator = exceptionTranslator; this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor()); }
会对SqlSessionFactory生成代理,实际调用这个代理的方法
public <T> T selectOne(String statement) {
return this.sqlSessionProxy.selectOne(statement);
}
1. 进入SqlSessionTemplate.SqlSessionInterceptor
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
......
Object t = method.invoke(sqlSession, args);
......
}
看SqlSessionUtils.getSqlSession方法:
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { Assert.notNull(sessionFactory, "No SqlSessionFactory specified"); Assert.notNull(executorType, "No ExecutorType specified"); SqlSessionHolder holder = (SqlSessionHolder)TransactionSynchronizationManager.getResource(sessionFactory); if(holder != null && holder.isSynchronizedWithTransaction()) { if(holder.getExecutorType() != executorType) { throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction"); } else { holder.requested(); if(logger.isDebugEnabled()) { logger.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction"); } return holder.getSqlSession(); } } else {//进入这里呀呀呀 if(logger.isDebugEnabled()) { logger.debug("Creating a new SqlSession"); }
//step 1.1 SqlSession session = sessionFactory.openSession(executorType); if(TransactionSynchronizationManager.isSynchronizationActive()) { Environment environment = sessionFactory.getConfiguration().getEnvironment(); if(environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) { if(logger.isDebugEnabled()) { logger.debug("Registering transaction synchronization for SqlSession [" + session + "]"); } //step 1.2 holder = new SqlSessionHolder(session, executorType, exceptionTranslator); TransactionSynchronizationManager.bindResource(sessionFactory, holder); TransactionSynchronizationManager.registerSynchronization(new SqlSessionUtils.SqlSessionSynchronization(holder, sessionFactory)); holder.setSynchronizedWithTransaction(true); holder.requested(); } else { if(TransactionSynchronizationManager.getResource(environment.getDataSource()) != null) { throw new TransientDataAccessResourceException("SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization"); } if(logger.isDebugEnabled()) { logger.debug("SqlSession [" + session + "] was not registered for synchronization because DataSource is not transactional"); } } } else if(logger.isDebugEnabled()) { logger.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active"); } return session; } }
1.1 进入DefaultSqlSessionFactory openSession方法:
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) { Transaction tx = null; DefaultSqlSession var8; try { Environment e = this.configuration.getEnvironment();
//springManagedTransactionFactory TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(e); tx = transactionFactory.newTransaction(e.getDataSource(), level, autoCommit); Executor executor = this.configuration.newExecutor(tx, execType, autoCommit); var8 = new DefaultSqlSession(this.configuration, executor); } catch (Exception var12) { this.closeTransaction(tx); throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12); } finally { ErrorContext.instance().reset(); } return var8; }
进入SpringManagedTransactionFactory的
newTransaction(e.getDataSource(), level, autoCommit);
返回
return new SpringManagedTransaction(dataSource);
这个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);
if(this.logger.isDebugEnabled()) {
this.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()) { logger.debug("Fetching JDBC Connection from DataSource"); Connection con = dataSource.getConnection(); if(TransactionSynchronizationManager.isSynchronizationActive()) { logger.debug("Registering transaction synchronization for JDBC Connection"); ConnectionHolder holderToUse = conHolder; if(conHolder == null) { holderToUse = new ConnectionHolder(con); } else { conHolder.setConnection(con); } holderToUse.requested(); TransactionSynchronizationManager.registerSynchronization(new DataSourceUtils.ConnectionSynchronization(holderToUse, dataSource)); holderToUse.setSynchronizedWithTransaction(true); if(holderToUse != conHolder) { TransactionSynchronizationManager.bindResource(dataSource, holderToUse); } } return con; } else { conHolder.requested(); if(!conHolder.hasConnection()) { logger.debug("Fetching resumed JDBC Connection from DataSource"); conHolder.setConnection(dataSource.getConnection()); } return conHolder.getConnection(); } }
这一步就和 spring--事务原理 中分析的对接了!!!connection连接对象来自当前线程绑定的ConnectionHolder中的connection对象
最终 DefaultSqlSession-》Executor-》Transaction-》当前线程绑定的ConnectionHolder中的connection对象
1.2 构建SqlSessionHolder-》DefaultSqlSession,并绑定到当前线程<sessionFactory,session holder>
2. DefaultSqlSession的执行见 mybatis缓存