1、产生的背景
使用MyBatis
就要保证SqlSession
实例的线程安全,就必须要为每一次的请求单独创建一个SqlSession
。但如果每一次请求都要用openSession()
自己去创建,就比较麻烦了。
所以在spring
中,我们使用的mybatis-spring
包中提供了一个线程安全的SqlSession
的包装类sqlSessionTemplate
,用它来替代SqlSession
.因为他是线程安全的,所以可以在所有的Service层来共享一个实例(默认为单例)。
这个跟Spring
封装其他的组件是一样的,比如JdbcTemplate, RedisTemplate
等等,也是 Spring
跟MyBatis
整合的最关键的一个类。
2、创建SqlSessionTemplate
2.1 生成代理对象
SqlSessionTemplate
里面有DefaultSqlSession
的所有的方法:select One()、select List()、insert()、update()、delete(),不过它都是通过一个代理对象实现的。这个代理对象在构造方法里面通过一个代理类创建:
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
notNull(executorType, "Property 'executorType' is required");
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
//创建一个代理类,被代理的对象实现 SqlSession接口,代理类为SqlSessionInterceptor
this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(),
new Class[] {
SqlSession.class }, new SqlSessionInterceptor());
}
所有的方法都会先走到内部代理类 SqlSessionInterceptor
的 invoke()
方法:
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//获取新的sqlSession,此处的为线程安全的sqlSession(使用了threadLocal)
SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args);
。。。
return result;
} catch (Throwable t) {
。。。。。。。。。。。。。。。。
}
}
在使用SqlSessionTemplate
调用方法的时候,先调用代理对象SqlSessionInterceptor
的invoke()
方法,通过getSqlSession()
获取一个新的sqlSession对象,保证了每个请求是生成一个sqlSession,确保了线程安全。
2.2、获取SqlSession
首先会使用工厂类、执行器类型、异常解析器创建一个 sqlSession
,然后再调用
sqlSession
的实现类,实际上就是在这里调用了 DefaultSqlSession
的方法。此处调用的getSqlSession()
方法用来获取一个SqlSession
对象。
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) {
notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);
//获取SqlSessionHolder
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
SqlSession session = sessionHolder(executorType, holder);
if (session != null) {
return session;
}
LOGGER.debug(() -> "Creating a new SqlSession");
session = sessionFactory.openSession(executorType);
registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
return session;
}
TransactionSynchronizationManager
获取当前线程threadLocal
是否有SqlSessionHolder
,如果有就从SqlSessionHolder
取出当前SqlSession
,如果当前线程threadLocal
没有SqlSessionHolder
,就从sessionFactory
中创建一个SqlSession
,最后注册会话到当前线程threadLocal
中。
2.3 事务管理器
public abstract class TransactionSynchronizationManager {
private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);
// 存储当前线程事务资源,比如Connection、session等
private static final ThreadLocal<Map<Object, Object></