读完这篇文章,你将会知道:
- SqlSessionTemplate 和 SqlSessionManager 有什么不同。
- SqlSessionTemplate 如何实现线程安全。
- SqlSessionTemplate 怎么和数据库打交道。
目录
SqlSessionTemplate 和 SqlSessionManager 有什么不同。
PersistenceExceptionTranslator:处理持久化框架的异常
SqlSessionTemplate 和 SqlSessionManager 有什么不同
SqlSessionTemplate是Mybatis为了接入Spring提供的Bean。通过TransactionSynchronizationManager中的ThreadLocal<Map<Object, Object>>保存线程对应的SqlSession,实现session的线程安全。
SqlSessionManager是Mybatis不接入Spring时用于管理SqlSession的Bean。通过SqlSessionManagger的ThreadLocal<SqlSession>实现session的线程安全。
SqlSessionTemplate里面有4个类变量
字段 | 类型 | 描述 |
sqlSessionFactory | SqlSessionFactory | session工厂 |
executorType | ExecutorType | Executor的类型:SIMPLE, REUSE, BATCH |
sqlSessionProxy | SqlSession | SqlSession代理对象,注册了SqlSessionInterceptor反射处理器,实际上的方法调用都是通过SqlSessionInterceptor反射实现的。 |
exceptionTranslator | PersistenceExceptionTranslator | Spring提供的接口,用于处理持久化框架的异常 |
SqlSessionTemplate实际上是通过内部类SqlSessionInterceptor提供的反射功能去执行具体的操作。
下图是SqlSessionTemplate的构造函数中,sqlSessionProxy的构建方式,通过注册SqlSessionInterceptor这个反射处理器去执行SqlSession中的方法。
SqlSessionTemplate 如何实现线程安全
在进行反射的时候,invoke通过getSqlSession方法拿到DefaultSqlSession实例,getSqlSession方法里面处理了sqlSession的线程安全问题(通过ThreadLocal实现)。
下面详细讲解 getSqlSession() 是如何工作的:
(1)getSqlSession方法中,在资源同步管理器上获取资源(SqlSessionHolder),SqlSessionHolder实际上可认为是SqlSession的一层包装
(2)在TransactionSynchronizationManager.getResource方法中,根据key生成一个autualKey,然后通过doGetResource方法获得对应的SqlSessionHolder。
(3)在doGetResource(key)中,会用到resources这个 ThreadLocal<Map<Object, Object>> 对象,每个线程通过维护自己的recources资源(包括SqlSessionHolder)来保证线程安全。
SqlSessionTemplate 怎么和数据库打交道
SqlSessionTemplate不直接和数据库打交道,实际上SqlSessionTemplate调用的还是DefaultSqlSession这个类,由DefaultSqlSession去做具体的事情。
那么SqlSessionTemplate中的DefaultSqlSession是怎么来的呢?
我们继续看getSqlSession方法,在getSqlSession中,如果当前线程拿不到session,就是调用sqlSessionFacatory的opernSession方法,开启一个会话。
在SqlSessionTemplate中,sqlSessionFacatory实际上的实现是“DefaultSqlSessionFacatory”。
sessionFactory会创建事务、Executor,最终生成一个新的DefualtSqlSession对象。
ExecutorType:Executor的类型
类型 | 实例化对象 | 描述 |
SIMPLE | SimpleExecutor | 每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。 |
REUSE | ReuseExecutor | 可复用Statement。执行update或select时,使用sql作为key在 Map<String, Statement> statementMap 中获得Statement(Statement或PrepareStatement),存在就使用,不存在就创建;用完后,不关闭Statement对象。 |
BATCH | BatchExecutor | 批量执行update(jdbc批处理不支持select)。 |
PersistenceExceptionTranslator:处理持久化框架的异常
Spring提供的接口,用于处理持久化框架的异常。