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>

最低0.47元/天 解锁文章
816

被折叠的 条评论
为什么被折叠?



