欢迎光临
我们一直在努力

MybatisSqlSessionTemplate源码解析

Mybatis sqlsessionTemplate 源码解析

在使用Mybatis与Spring集成的时候我们用到了SqlSessionTemplate 这个类。

 

 

通过源码我们何以看到 SqlSessionTemplate 实现了SqlSession接口,也就是说我们可以使用SqlSessionTemplate 来代理以往的DefailtSqlSession完成对数据库的操作,但是DefailtSqlSession这个类不是线程安全的,所以这个类不可以被设置成单例模式的。

如果是常规开发模式 我们每次在使用DefailtSqlSession的时候都从sqlsessionfactory当中获取一个就可以了。但是与Spring集成以后,Spring提供了一个全局唯一的SqlSessionTemplate示例 来完成DefailtSqlSession的功能,问题就是:无论是多个dao使用一个SqlSessionTemplate,还是一个dao使用一个SqlSessionTemplate,SqlSessionTemplate都是对应一个sqlSession,当多个web线程调用同一个dao时,它们使用的是同一个SqlSessionTemplate,也就是同一个SqlSession,那么它是如何确保线程安全的呢?让我们一起来分析一下。

(1)首先,通过如下代码创建代理类,表示创建SqlSessionFactory的代理类的实例,该代理类实现SqlSession接口,定义了方法拦截器,如果调用代理类实例中实现SqlSession接口定义的方法,该调用则被导向SqlSessionInterceptor的invoke方法

 

核心代码就在 SqlSessionInterceptor的invoke方法当中。

在上面的invoke方法当中使用了俩个工具方法 分别是

SqlSessionUtils.getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator)

SqlSessionUtils.closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory)

那么这个俩个方法又是如何与Spring的事物进行关联的呢?

 1 public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {  2 //根据sqlSessionFactory从当前线程对应的资源map中获取SqlSessionholder,当sqlSessionFactory创建了sqlSession,就会在事务管理器中添加一对映射:key为sqlSessionFactory,value为SqlSessionHolder,该类保存sqlSession及执行方式   3 SqlSessionHolder holder = (SqlSessionHolder) getResource(sessionFactory);  4 //如果holder不为空,且和当前事务同步   5 if (holder != null && holder.isSynchronizedWithTransaction()) {  6 //hodler保存的执行类型和获取SqlSession的执行类型不一致,就会抛出异常,也就是说在同一个事务中,执行类型不能变化,原因就是同一个事务中同一个sqlSessionFactory创建的sqlSession会被重用   7 if (holder.getExecutorType() != executorType) {  8 throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction");  9  } 10 //增加该holder,也就是同一事务中同一个sqlSessionFactory创建的唯一sqlSession,其引用数增加,被使用的次数增加  11  holder.requested(); 12 //返回sqlSession  13 return holder.getSqlSession(); 14  } 15 //如果找不到,则根据执行类型构造一个新的sqlSession  16 SqlSession session = sessionFactory.openSession(executorType); 17 //判断同步是否激活,只要SpringTX被激活,就是true  18 if (isSynchronizationActive()) { 19 //加载环境变量,判断注册的事务管理器是否是SpringManagedTransaction,也就是Spring管理事务  20 Environment environment = sessionFactory.getConfiguration().getEnvironment(); 21 if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) { 22 //如果是,则将sqlSession加载进事务管理的本地线程缓存中  23 holder = new SqlSessionHolder(session, executorType, exceptionTranslator); 24 //以sessionFactory为key,hodler为value,加入到TransactionSynchronizationManager管理的本地缓存ThreadLocal<Map<Object, Object>> resources中  25  bindResource(sessionFactory, holder); 26 //将holder, sessionFactory的同步加入本地线程缓存中ThreadLocal<Set<TransactionSynchronization>> synchronizations  27 registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory)); 28 //设置当前holder和当前事务同步  29 holder.setSynchronizedWithTransaction(true); 30 //增加引用数  31  holder.requested(); 32 } else { 33 if (getResource(environment.getDataSource()) == null) { 34 } else { 35 throw new TransientDataAccessResourceException( 36 "SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization"); 37  } 38  } 39 } else { 40  } 41 return session; 42 } 

其实通过上面的代码我们可以看出 Mybatis在很多地方都用到了代理模式,这个模式可以说是一种经典模式,其实不紧紧在Mybatis当中使用广泛,Spring的事物,AOP ,连接池技术 等技术都使用了代理技术。在后面的文章中我们来分析Spring的抽象事物管理机制。

 

 

  • 海报
海报图正在生成中...
赞(0) 打赏
声明:
1、本博客不从事任何主机及服务器租赁业务,不参与任何交易,也绝非中介。博客内容仅记录博主个人感兴趣的服务器测评结果及一些服务器相关的优惠活动,信息均摘自网络或来自服务商主动提供;所以对本博客提及的内容不作直接、间接、法定、约定的保证,博客内容也不具备任何参考价值及引导作用,访问者需自行甄别。
2、访问本博客请务必遵守有关互联网的相关法律、规定与规则;不能利用本博客所提及的内容从事任何违法、违规操作;否则造成的一切后果由访问者自行承担。
3、未成年人及不能独立承担法律责任的个人及群体请勿访问本博客。
4、一旦您访问本博客,即表示您已经知晓并接受了以上声明通告。
文章名称:《MybatisSqlSessionTemplate源码解析》
文章链接:https://www.456zj.com/19150.html
本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址