一、SqlSessionTemplate的入场
spring在集成mybatis 的时候,并没有使用DefaultSqlSession来一个个getmapper。而是通过@Autowired来直接获取mapper接口,调用mapper方法。那么spring帮助自动注入的mapper到底是什么呢?
其实是一种名为MapperFactoryBean的类,这个类继承了SqlSessionDaoSupport,可以直接获取到SqlSessionTemplate。使用SqlSessionTemplate来代理DefaultSqlSession进行db交互。
那么这个SqlSessionTemplate到底是何方神圣?
SqlSessionTemplate其实是Spring 为了接入mybatis提供的bean,它其实是SqlSession的一个实现类,用于替代DefaultSqlSession的存在,保存线程的SqlSession来保证线程安全性。
既然SqlSessionTemplate是一个Bean,那它默认就是单利的,里面有一个sqlSessionProxy的类变量,他其实是SqlSession的代理类:SqlSessionInterceptor。每次SqlSessionTemplate在执行方法的时候,最后都给交给SqlSessionInterceptor来代理执行,SqlSessionInterceptor每次在获取SqlSession的时候,都会使用事务管理器从threadlocal中获取,所以必然是线程安全的!对于Spring而言,每个事务都会使用同一个SqlSession,其实也就是DefaultSqlSession,用于操作相应的executor来进行db交互。
是不是看到这里有点懵逼?接下来结合源码来进一步分析。
从你依赖注入一个mapper接口到完成一次sql查询的全过程
二、结合源码分析
例:TestMapper.java TestMapper.xml
通过@Autowire来获取一个TestMapper,但其实spring在启动的时候注入的是一个MapperFactoryBean(具体位置在org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions中)
下面看看MapperFactoryBean的源码
// 继承了SqlSessionDaoSupport,继承了SqlSessionDaoSupport可以用于直接获取SqlsessionTemplate
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
// 真正的mapper文件
private Class<T> mapperInterface;
public MapperFactoryBean() {
//intentionally empty
}
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
...
}
再来看看通过SqlSessionDaoSupport获取到的SqlSessionTemplate里面是什么:
// 其实为defaultSqlSession的代理类SqlSessionInterceptor
private final SqlSession sqlSessionProxy;
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;
// jdk动态代理
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] {
SqlSession.class },
new SqlSessionInterceptor());
}
...
// 内部类 SqlSessionInterceptor
private class SqlSessionInterceptor implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// SqlSessionUtils.getSession(...) 是工具类, 里面使用事务同步管理器从threadlocal中获取到SqlsessionHolder, sqlsessionholder可以用于获取缓存了的DefaultSqlSession
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory