在Spring?Boot中MyBatis?的自動提交行為全解析(最新整理)
在 Spring Boot 中,MyBatis 的“自動提交”行為并不是 MyBatis 自己實現(xiàn)的,而是 由 Spring 框架通過事務管理器(PlatformTransactionManager)統(tǒng)一控制的。MyBatis 原生默認是 不自動提交(autoCommit=false),但在 Spring Boot 集成環(huán)境下,是否提交由 Spring 的事務傳播機制決定:
一、核心結論
| 場景 | 是否自動提交? | 控制者 |
|---|---|---|
| 原生 MyBatis(無 Spring) | ? 默認不提交,需手動 sqlSession.commit() | MyBatis 自身 |
Spring Boot + MyBatis(無 @Transactional) | ? 自動提交(每條 SQL 獨立事務) | Spring 的 DataSourceTransactionManager |
Spring Boot + MyBatis(有 @Transactional) | ? 方法結束前不提交,成功則提交,異常則回滾 | Spring 事務管理 |
? 所以你看到的“自動提交”,其實是 Spring 在方法無事務注解時,為每個數(shù)據(jù)庫操作開啟并立即提交一個獨立事務。
二、Spring Boot 如何集成 MyBatis?
Spring Boot 通過 mybatis-spring-boot-starter 自動配置:
- 創(chuàng)建
SqlSessionFactory - 創(chuàng)建
SqlSessionTemplate(線程安全的 SqlSession 代理) - 注冊 Mapper 接口為 Spring Bean
關鍵點:不再直接使用原生 SqlSession,而是通過 SqlSessionTemplate 代理調用。
三、源碼分析:為什么“自動提交”?
1.SqlSessionTemplate的代理機制
SqlSessionTemplate 是 MyBatis-Spring 提供的線程安全 SqlSession 實現(xiàn),它內部持有一個 SqlSessionInterceptor(動態(tài)代理)。
當調用 Mapper 方法(如 userMapper.insert(user))時,實際執(zhí)行路徑:
Mapper Proxy → SqlSessionTemplate → SqlSessionInterceptor.invoke()
查看 SqlSessionInterceptor.invoke() 源碼(簡化版):
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1. 獲取當前 Spring 管理的 SqlSession(可能已存在事務上下文)
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator
);
try {
// 2. 執(zhí)行 SQL(如 insert/update/delete/select)
Object result = method.invoke(sqlSession, args);
// 3. 如果當前沒有 Spring 事務,則立即 commit(僅對更新操作)
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
sqlSession.commit(true); // true 表示強制提交
}
return result;
} catch (Throwable t) {
// 異常處理...
throw t;
} finally {
// 4. 如果不是 Spring 事務管理的 SqlSession,則關閉它
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
sqlSession.close();
}
}
}?? 關鍵判斷:isSqlSessionTransactional(...)
- 如果當前線程 已有 Spring 事務(即處于
@Transactional方法中),則返回true,不提交、不關閉,交由 Spring 統(tǒng)一管理。 - 如果 沒有 Spring 事務,則返回
false,立即提交并關閉 SqlSession。
這就解釋了“自動提交”的來源!
2.isSqlSessionTransactional的實現(xiàn)邏輯
該方法檢查當前 SqlSession 是否被 Spring 事務管理:
// org.mybatis.spring.SqlSessionUtils
public static boolean isSqlSessionTransactional(SqlSession session, SqlSessionFactory sessionFactory) {
// 從 ThreadLocal 中獲取 Spring 管理的 SqlSession
SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager
.getResource(sessionFactory);
return (holder != null) && (holder.getSqlSession() == session);
}TransactionSynchronizationManager.getResource()是 Spring 事務同步的核心機制。- 只有在
@Transactional方法中,Spring 才會提前將SqlSession綁定到ThreadLocal。 - 否則,
holder == null,返回false→ 觸發(fā)自動提交。
3. Spring 事務如何接管 SqlSession?
當方法標注 @Transactional 時,Spring 會:
- 在方法開始前,通過
DataSourceTransactionManager開啟 JDBC 事務(connection.setAutoCommit(false))。 - 調用
SqlSessionUtils.getSqlSession()時,發(fā)現(xiàn)已有事務,復用同一個 Connection,并將其包裝為SqlSession存入ThreadLocal。 - 方法結束時,根據(jù)是否拋異常,調用
commit()或rollback()。 - 最終由 Spring 負責
close()。
此時,SqlSessionTemplate 不會干預提交行為。
四、驗證實驗
場景 1:無@Transactional
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public void saveUser(User user) {
userMapper.insert(user); // 自動提交!
}
}? 插入成功,即使后續(xù)代碼拋異常,數(shù)據(jù)也不會回滾。
場景 2:有@Transactional
@Transactional
public void saveUserWithTx(User user) {
userMapper.insert(user);
throw new RuntimeException("模擬異常"); // 數(shù)據(jù)會回滾!
}? 插入被回滾,因為整個方法是一個事務。
五、配置項說明
雖然 MyBatis 有 autoCommit 配置,但在 Spring Boot 中 幾乎無效,因為:
- Spring 通過
DataSource獲取Connection,并由事務管理器控制setAutoCommit()。 - MyBatis 的
autoCommit參數(shù)在SqlSessionFactoryBean中會被忽略(或覆蓋)。
所以,不要依賴 MyBatis 的 autoCommit,而應使用 Spring 的 @Transactional。
六、總結
| 問題 | 答案 |
|---|---|
| Spring Boot 中 MyBatis 為何“自動提交”? | 因為 Spring 在無事務方法中,為每次 Mapper 調用創(chuàng)建獨立事務并立即提交。 |
| 源碼關鍵類 | SqlSessionTemplate.SqlSessionInterceptor + SqlSessionUtils |
| 控制提交行為的方式 | 使用 @Transactional 注解,而非 MyBatis 配置 |
| 是否應關閉“自動提交”? | 不需要關閉,這是 Spring 的合理默認行為;需事務時加 @Transactional 即可 |
?? 最佳實踐:
- 簡單查詢/單條寫入:無需
@Transactional,享受自動提交。 - 多操作一致性要求:必須加
@Transactional。 - 永遠不要在 Service 層手動調用
sqlSession.commit()!
通過 Spring 的聲明式事務,開發(fā)者既能獲得“自動提交”的便利,又能靈活控制復雜事務,這正是 Spring Boot + MyBatis 的強大之處。
到此這篇關于在Spring Boot中MyBatis 的自動提交行為全解析(最新整理)的文章就介紹到這了,更多相關Spring Boot MyBatis 自動提交內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot中加載與Bean處理的細節(jié)剖析教程
這篇文章主要為大家詳細介紹了SpringBoot中加載與Bean處理的細節(jié)剖析,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2025-08-08
Lombok 的@StandardException注解解析
@StandardException 是一個實驗性的注解,添加到 Project Lombok 的 v__1.18.22 版本中,在本教程中,我們將使用 Lombok 的 @StandardException 注解自動生成異常類型類的構造函數(shù),需要的朋友可以參考下2023-05-05
Spring Boot應用程序同時支持HTTP和HTTPS協(xié)議的實現(xiàn)方法
如今,企業(yè)級應用程序的常見場景是同時支持HTTP和HTTPS兩種協(xié)議,這篇文章考慮如何讓Spring Boot應用程序同時支持HTTP和HTTPS兩種協(xié)議,需要的朋友可以參考下2019-10-10
java實現(xiàn)二分法查找出數(shù)組重復數(shù)字
這篇文章主要為大家詳細介紹了java實現(xiàn)二分法查找出數(shù)組重復數(shù)字,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-11-11
SpringBoot+JPA?分頁查詢指定列并返回指定實體方式
這篇文章主要介紹了SpringBoot+JPA?分頁查詢指定列并返回指定實體方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12

