Spring+MyBatis源码解析之SqlSessionTemplate

1、产生的背景

使用MyBatis就要保证SqlSession实例的线程安全,就必须要为每一次的请求单独创建一个SqlSession。但如果每一次请求都要用openSession()自己去创建,就比较麻烦了。

​ 所以在spring中,我们使用的mybatis-spring包中提供了一个线程安全的SqlSession的包装类sqlSessionTemplate,用它来替代SqlSession.因为他是线程安全的,所以可以在所有的Service层来共享一个实例(默认为单例)。

​ 这个跟Spring封装其他的组件是一样的,比如JdbcTemplate, RedisTemplate 等等,也是 SpringMyBatis 整合的最关键的一个类。

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());
  }

所有的方法都会先走到内部代理类 SqlSessionInterceptorinvoke()方法:

 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调用方法的时候,先调用代理对象SqlSessionInterceptorinvoke()方法,通过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></
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值