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

