讀完這篇文章,你將會知道:
- 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提供的接口,用於處理持久化框架的異常。