多數(shù)據(jù)源下@transactional事務(wù)踩坑實(shí)戰(zhàn)指南
多數(shù)據(jù)源使用DynamicDatasource,再用@Transactiona注解,造成數(shù)據(jù)源會(huì)切換的BUG:
- 方法上寫了
@DS("slave") - 執(zhí)行 SQL 時(shí)卻仍然走了
master
情景浮現(xiàn):
@DS("master")
public class DB1Service{
public list<?> queryDB1()
}
@DS("slaver")
public class DB2Service{
public list<?> queryDB2()
}
public class Main{
@Transactional(rollbackFor = Exception.class)
public void sync(){
// 預(yù)期會(huì)走slaver庫(kù),?? 但實(shí)際還是會(huì)查詢 master DB
var list2 = DB2Service.queryDB2()
// .....
var list1 = DB1Service.queryDB1()
}
}
1 為什么?
先說(shuō)結(jié)論 :
在同一個(gè)本地事務(wù)里,第一次拿到的連接會(huì)綁定到當(dāng)前線程。后續(xù)再切@DS,通常只會(huì)改路由標(biāo)識(shí),不會(huì)替換已經(jīng)綁定的連接。
調(diào)用 sync() 時(shí),大致發(fā)生下面幾步:
- 進(jìn)入
@Transactional代理,事務(wù)開始 - 事務(wù)管理器通過(guò)
DataSourceUtils.getConnection(...)拿連接 - 連接綁定到
TransactionSynchronizationManager(ThreadLocal) - 執(zhí)行業(yè)務(wù)代碼,進(jìn)入
db2Service.queryDB2() @DS("slave")把當(dāng)前線程的數(shù)據(jù)源 key 改成slave- 但取連接時(shí)發(fā)現(xiàn)線程里已經(jīng)有事務(wù)連接,于是直接復(fù)用
- SQL 繼續(xù)走原連接(常見是
master)
這里最重要的一點(diǎn): @DS 決定的是 “下一次新建連接時(shí)選哪個(gè)數(shù)據(jù)源”,不是“把當(dāng)前事務(wù)里的連接熱切換”。
如果連接已經(jīng)在事務(wù)里綁定好了,它不會(huì)換連接。
2 擴(kuò)展:Dynamic-Datasource實(shí)現(xiàn)多數(shù)據(jù)源原理
啟動(dòng)階段裝配
• DynamicDataSourceAutoConfiguration 注冊(cè) DynamicRoutingDataSource 作為主 DataSource。
• 把你配置的 spring.datasource.dynamic.datasource.* 加載成數(shù)據(jù)源池,維護(hù)在內(nèi)部 dataSourceMap/groupDataSources 里。AOP 攔截 @DS
• DynamicDataSourceAopConfiguration 裝配 DynamicDataSourceAnnotationAdvisor + Interceptor。
• 方法進(jìn)入時(shí),DynamicDataSourceAnnotationInterceptor 解析 @DS 值(DataSourceClassResolver,支持方法/類、接口、繼承等)。
• 解析出的 key(如 master/doris)被 push 到
DynamicDataSourceContextHolder(ThreadLocal,棧結(jié)構(gòu),支持嵌套調(diào)用)。
• 方法退出后 poll,恢復(fù)上一個(gè)數(shù)據(jù)源上下文。真正路由發(fā)生在“取連接” • JdbcTemplate/MyBatis 最終都會(huì)走到當(dāng)前主數(shù)據(jù)源取連接。
• 主數(shù)據(jù)源是 DynamicRoutingDataSource,它在 determineDataSource() 里 peek 當(dāng)前線程 key。
• 然后 getDataSource(key):
• key 為空 -> 用 primary(默認(rèn) master)
• key 是具體庫(kù)名 -> 直連該庫(kù)
• key 是組名 -> 按策略(默認(rèn)負(fù)載均衡)選組內(nèi)某個(gè)庫(kù)
• 未命中時(shí):strict=true 拋異常,strict=false 回退 primary
總結(jié):
• @DS 只是改“路由上下文”
• DynamicRoutingDataSource 在取連接時(shí)按上下文選庫(kù)
• 不是直接“切換已拿到的連接”
到此這篇關(guān)于多數(shù)據(jù)源下@transactiona事務(wù)踩坑實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)多數(shù)據(jù)源下@transactiona事務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java?事務(wù)注解@Transactional回滾(try?catch、嵌套)問(wèn)題
- Spring中@Transactional用法詳細(xì)介紹
- springboot中事務(wù)管理@Transactional的注意事項(xiàng)與使用場(chǎng)景
- Spring @Transactional工作原理詳解
- @Transactional注解:多個(gè)事務(wù)嵌套時(shí),獨(dú)立事務(wù)處理方式
- Java注解@Transactional事務(wù)類內(nèi)調(diào)用不生效問(wèn)題及解決辦法
- 帶有@Transactional和@Async的循環(huán)依賴問(wèn)題的解決
相關(guān)文章
springboot配置文件屬性變量引用方式${}和@@用法及區(qū)別說(shuō)明
這篇文章主要介紹了springboot配置文件屬性變量引用方式${}和@@用法及區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
IDEA基于支付寶小程序搭建springboot項(xiàng)目的詳細(xì)步驟
這篇文章主要介紹了IDEA基于支付寶小程序搭建springboot項(xiàng)目的詳細(xì)步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-04-04
Java實(shí)現(xiàn)整數(shù)的逆序輸出的三種方法
這篇文章主要介紹了Java實(shí)現(xiàn)整數(shù)的逆序輸出的三種方法,第一種是無(wú)限制整數(shù)的逆序輸出,第二種是非負(fù)整數(shù)的逆序輸出,第三種是非特殊情況的逆序輸出,每種方法給大家講解的非常詳細(xì)需要的朋友可以參考下2022-11-11
Java使用BigDecimal確保數(shù)值計(jì)算精度的最佳實(shí)踐指南
這篇文章主要為大家詳細(xì)介紹了Java使用BigDecimal確保數(shù)值計(jì)算精度的相關(guān)知識(shí),BigDecimal一般適用于金融計(jì)算、高精度運(yùn)算等對(duì)數(shù)值準(zhǔn)確性要求高的場(chǎng)景,下面小編就和大家詳細(xì)介紹一下吧2026-01-01
mybatis如何設(shè)置useGeneratedKeys=true
這篇文章主要介紹了mybatis如何設(shè)置useGeneratedKeys=true,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。2022-01-01
SpringBoot 集成 MyBatis/MyBatis-Plus 超詳細(xì)教程
本文詳細(xì)介紹了SpringBoot集成MyBatis和MyBatis-Plus的完整流程,包括數(shù)據(jù)源配置、Mapper掃描、XML映射等,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2026-06-06
關(guān)于@RequestParam和@RequestBody的用法及說(shuō)明
本文主要介紹了Spring框架中參數(shù)綁定相關(guān)的三個(gè)注解:@RequestParam、@ModelAttribute和@RequestBody的使用場(chǎng)景和區(qū)別,通過(guò)比較它們的使用場(chǎng)景和注意事項(xiàng),幫助讀者快速理解并正確使用這些注解,避免在項(xiàng)目開發(fā)中出現(xiàn)常見問(wèn)題2026-03-03

