MyBatis sqlSession概要梳理
工作中,需要學習一下MyBatis sqlSession的產生過程,翻看了mybatis-spring的原始碼,閱讀了一些mybatis的相關doc,對mybatis sqlSession有了一些認知和理解,這裡簡單的總結和整理一下。
首先, 通過翻閱原始碼,我們來整理一下mybatis進行持久化操作時重要的幾個類:
-
SqlSessionFactoryBuilder:build方法建立SqlSessionFactory例項。
-
SqlSessionFactory:建立SqlSession例項的工廠。
-
SqlSession:用於執行持久化操作的物件,類似於jdbc中的Connection。
-
SqlSessionTemplate:MyBatis提供的持久層訪問模板化的工具,執行緒安全,可通過構造引數或依賴注入SqlSessionFactory例項。
Hibernate是與MyBatis類似的orm框架,這裡與Hibernate進行一下對比,Hibernate中對於connection的管理,是通過以下幾個重要的類:
-
SessionFactory:建立Session例項的工廠,類似於MyBatis中的SqlSessionFactory。
-
Session:用來執行持久化操作的物件,類似於jdbc中的Connection。
-
HibernateTemplate:Hibernate提供的持久層訪問模板化的工具,執行緒安全,可通過構造引數或依賴注入SessionFactory例項。
在日常的開發中,我們經常需要這樣對MyBatis和Spring進行整合,把sqlSessionFactory交給Spring管理,通常情況下,我們這樣配置:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
通過上面的配置,Spring將自動建立一個SqlSessionFactory物件,其中使用到了org.mybatis.spring.SqlSessionFactoryBean,其 是MyBatis為Spring提供的用於建立SqlSessionFactory的類,將在Spring應用程式的上下文建議一下可共享的 MyBatis SqlSessionFactory例項,我們可以通過依賴注入將SqlSessionFactory傳遞給MyBatis的一些介面。
如果通過Spring進行事務的管理,我們需要增加Spring註解的事務管理機制,如下配置:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven/>
這樣,我們就可以使用Spring @Transactional註解,進行事務的控制,表明所註釋的方法應該在一個事務中執行。 Spring將在事務成功完成後提交事務,在事務發生錯誤時進行異常回滾,而且,Spring會將產生的MyBatis異常轉換成適當的 DataAccessExceptions,從而提供具體的異常資訊。
下面,我們通過分析SqlSessionUtils中getSession的原始碼,來詳細的瞭解一下sqlSession的產生過程,原始碼如下:
public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
notNull(sessionFactory, "No SqlSessionFactory specified");
notNull(executorType, "No ExecutorType specified");
SqlSessionHolder holder = (SqlSessionHolder) getResource(sessionFactory);
if (holder != null && holder.isSynchronizedWithTransaction()) {
if (holder.getExecutorType() != executorType) {
throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction");
}
holder.requested();
if (logger.isDebugEnabled()) {
logger.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction");
}
return holder.getSqlSession();
}
if (logger.isDebugEnabled()) {
logger.debug("Creating a new SqlSession");
}
SqlSession session = sessionFactory.openSession(executorType);
// Register session holder if synchronization is active (i.e. a Spring TX is active)
//
// Note: The DataSource used by the Environment should be synchronized with the
// transaction either through DataSourceTxMgr or another tx synchronization.
// Further assume that if an exception is thrown, whatever started the transaction will
// handle closing / rolling back the Connection associated with the SqlSession.
if (isSynchronizationActive()) {
Environment environment = sessionFactory.getConfiguration().getEnvironment();
if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) {
if (logger.isDebugEnabled()) {
logger.debug("Registering transaction synchronization for SqlSession [" + session + "]");
}
holder = new SqlSessionHolder(session, executorType, exceptionTranslator);
bindResource(sessionFactory, holder);
registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory));
holder.setSynchronizedWithTransaction(true);
holder.requested();
} else {
if (getResource(environment.getDataSource()) == null) {
if (logger.isDebugEnabled()) {
logger.debug("SqlSession [" + session + "] was not registered for synchronization because DataSource is not transactional");
}
} else {
throw new TransientDataAccessResourceException(
"SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization");
}
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active");
}
}
return session;
}
上面的getSession方法,會從Spring的事務管理器中獲取一個SqlSession或建立一個新的SqlSession,將試圖從當前事務中得到一個SqlSession,然後,如果配置有事務管理器的工廠並且Spring 的事務管理器是活躍的,它將會鎖定當前事務的SqlSession,保證同步。主要是通過以下幾個步驟進行SqlSession的建立:
-
它會首先獲取SqlSessionHolder,SqlSessionHolder用於在TransactionSynchronizationManager中保持當前的SqlSession。
-
如果holder不為空,並且holder被事務鎖定,則可以通過holder.getSqlSession()方法,從當前事務中獲取sqlSession,即 Fetched SqlSession from current transaction。
-
如果不存在holder或沒有被事務鎖定,則會建立新的sqlSession,即 Creating a new SqlSession,通過sessionFactory.openSession()方法。
-
如果當前執行緒的事務是活躍的,將會為SqlSession註冊事務同步,即 Registering transaction synchronization for SqlSession。
相關文章
- Mybatis原理和SqlSessionMyBatisSQLSession
- Mybatis的核心——SqlSession解讀MyBatisSQLSession
- Mybatis原始碼解析4——SqlSessionMyBatis原始碼SQLSession
- 手寫自己的MyBatis框架-SqlSessionMyBatis框架SQLSession
- Mybatis詳解(二) sqlsession的建立過程MyBatisSQLSession
- MyBatis-06-Spring的SqlSession和原始區別MyBatisSpringSQLSession
- Mybatis環境搭建以及案例 SqlSession物件的方法MyBatisSQLSession物件
- Mybatis【2.2】-- Mybatis關於建立SqlSession原始碼分析的幾點疑問?MyBatisSQLSession原始碼
- 精盡MyBatis原始碼分析 - SqlSession 會話與 SQL 執行入口MyBatis原始碼SQLSession會話
- 【java深入學習第1章】深入探究 MyBatis-Spring 中 SqlSession 的原理與應用JavaMyBatisSpringSQLSession
- css概要CSS
- ExecutorService介面概要
- Redux 概要教程Redux
- Promise物件概要Promise物件
- 手寫SpringMvc概要SpringMVC
- IPSec組播概要
- 快取模式概要快取模式
- 軟體測試概要
- ORACLE 概要檔案管理Oracle
- 編譯系統概要編譯
- SQLT 概要和安裝SQL
- C++知識概要C++
- Easysearch 效能測試方法概要
- ChatGPT的終極指南概要ChatGPT
- Android 元件化架構概要Android元件化架構
- Activity梳理
- RxJava梳理RxJava
- 關係型資料庫概要資料庫
- Java——事件處理機制概要Java事件
- 軟體概要設計文件(終)
- 各廠商人機互動概要
- AMD 規範與CMD 規範概要
- Spark-Shuffle過程概要參考Spark
- 遊戲伺服器架構概要遊戲伺服器架構
- 對Tomcat的簡單概要小結Tomcat
- 社交系統ThinkSNS+技術概要
- 社交系統 ThinkSNS+ 技術概要
- JVM系列(五):gc實現概要01JVMGC