
SEATA Sharding-JDBC 分庫分表分布式事務完整實戰(zhàn)原理場景代碼優(yōu)缺點一、業(yè)務背景在海量數(shù)據高并發(fā)微服務場景中單庫單表會出現(xiàn)數(shù)據量大、查詢慢、寫入瓶頸、索引失效等問題行業(yè)普遍采用Sharding-JDBC做分庫分表、讀寫分離解決存儲與性能瓶頸。但分庫分表后會引入新的核心問題跨分片分布式事務。Sharding-JDBC 僅負責 SQL 路由、分片規(guī)則、多數(shù)據源管理不具備分布式事務一致性能力。當一次業(yè)務操作涉及多個分庫、多個分片表寫入/更新時本地事務只能保證單庫一致性必然出現(xiàn)部分分片成功、部分分片失敗的數(shù)據臟寫問題。因此生產環(huán)境必須引入SEATA AT 模式結合 Sharding-JDBC解決分庫分表場景下的跨分片分布式事務一致性問題實現(xiàn)分表擴容事務可控的高可用架構。二、核心適用場景SEATA Sharding-JDBC 組合方案并非所有項目都需要使用精準適配以下業(yè)務場景海量數(shù)據業(yè)務訂單、支付、流水、用戶行為數(shù)據單表數(shù)據量突破千萬/億級需要水平分表擴容高并發(fā)寫入場景秒殺、下單、流水記錄單庫寫入壓力過大需要分庫分擔IO壓力跨分片事務場景一次業(yè)務操作需要同時修改多個分片數(shù)據必須保證多分片同時成功/同時回滾高性能、低侵入訴求不想使用TCC硬編碼事務希望通過框架自動實現(xiàn)分布式事務讀寫分離分庫分表混合架構多數(shù)據源、多分片復雜架構下的數(shù)據一致性保障。不適用場景數(shù)據量小、并發(fā)低、單庫完全夠用的項目過度架構增加維護成本金融級強一致性核心賬務優(yōu)先Sharding-TCC模式。三、整合核心原理3.1 組件分工Sharding-JDBCJDBC層中間件負責攔截SQL、根據分片算法路由至對應分庫分表、管理多數(shù)據源、合并查詢結果SEATA AT模式負責跨分片分布式事務管控一階段記錄undo鏡像、二階段統(tǒng)一提交/回滾保證多分片數(shù)據最終一致。3.2 關鍵整合機制核心難點原生 SEATA 會通過DataSourceProxy代理數(shù)據源實現(xiàn)事務管控Sharding-JDBC 內部擁有自己的數(shù)據源分片代理邏輯。兩者直接整合會出現(xiàn)數(shù)據源代理沖突、事務失效。標準解決方案SEATA 嵌套代理 Sharding 數(shù)據源執(zhí)行鏈路業(yè)務SQL → SEATA數(shù)據源代理 → Sharding-JDBC分片路由 → 真實分庫數(shù)據源 → 執(zhí)行SQL并生成undo鏡像3.3 分片事務執(zhí)行流程TM開啟全局事務業(yè)務方法添加GlobalTransactional生成全局XIDSQL分片路由Sharding-JDBC 根據分片鍵路由到一個或多個分片庫表一階段預提交所有分片分支執(zhí)行SQLSEATA 生成每個分片的undo_log鏡像本地事務提交、釋放鎖二階段統(tǒng)一處理全局成功批量刪除所有分片undo_log事務正常結束全局異常根據各分片undo鏡像反向回滾所有分片數(shù)據保證多分片數(shù)據一致。四、方案優(yōu)缺點分析4.1 核心優(yōu)點零代碼侵入基于SEATA AT模式無需手動編寫Try/Confirm/Cancel僅注解開啟事務適配快速開發(fā)解決分片事務痛點徹底解決跨庫、跨分片部分成功、部分失敗的數(shù)據一致性問題高性能高并發(fā)一階段提交、短事務、無長鎖相比XA、TCC性能更高適配海量分片場景架構解耦分片擴容由Sharding管控事務一致性由SEATA管控職責清晰、擴展靈活兼容主流架構完美適配SpringCloud、MyBatis、MyBatis-Plus生態(tài)。4.2 現(xiàn)存缺點與生產局限存在臟讀風險AT模式一階段釋鎖高并發(fā)跨分片場景存在短暫臟讀、數(shù)據覆蓋風險極端場景會觸發(fā)鏡像校驗失敗、事務重試卡死不支持強隔離級別無法做到串行化隔離金融核心賬務場景不適用整合配置復雜多數(shù)據源、分片規(guī)則、事務分組配置不當極易出現(xiàn)事務不生效、代理沖突大事務風險放大跨多分片大事務一旦超時會出現(xiàn)多分片事務狀態(tài)割裂修復成本極高undo日志膨脹分片越多事務日志越多增加數(shù)據庫存儲與清理壓力。五、入門實戰(zhàn)SEATA Sharding-JDBC 完整整合案例5.0 整合核心常用注解及適配業(yè)務場景SEATA 結合 Sharding-JDBC 實現(xiàn)跨分片分布式事務核心依靠兩類注解實現(xiàn)事務管控與業(yè)務適配不同注解對應不同分片業(yè)務場景是入門開發(fā)與生產落地的核心重點下面結合分庫分表場景逐一說明。5.0.1 GlobalTransactionalSEATA 全局事務注解注解作用開啟跨庫、跨分片全局分布式事務是 SEATASharding-JDBC 整合的核心注解??山y(tǒng)一管控多個分片數(shù)據源的分支事務保證所有分片數(shù)據要么全部提交、要么全部回滾徹底解決分庫分表「部分分片成功、部分分片失敗」的一致性問題。核心屬性適配分片場景rollbackFor Exception.class捕獲所有業(yè)務異常任意分片報錯觸發(fā)全分片回滾適配跨多分片復雜業(yè)務timeout自定義全局事務超時時間解決跨多庫分片事務耗時過長導致的強制回滾失效問題propagation支持事務傳播配置適配多服務嵌套分片事務場景。貼合使用場景一次業(yè)務操作路由多個分庫、多個分片表的讀寫場景如用戶下單根據user_id分庫、order_id分表單次下單跨分片寫入跨分片數(shù)據聯(lián)動更新場景如下單同步扣減分片庫存、生成分片流水記錄高并發(fā)分片寫入場景需要嚴格保證多分片數(shù)據一致性禁止臟數(shù)據殘留。5.0.2 TransactionalSpring本地事務注解注解作用在 SEATASharding 整合架構中僅用于單分片本地事務兜底負責單個數(shù)據源內部的SQL事務控制不具備跨分片事務能力必須配合 GlobalTransactional 使用。貼合使用場景單個分片內多條SQL批量執(zhí)行保證單庫數(shù)據本地一致性作為全局事務的分支兜底輔助SEATA完成單分片事務提交與回滾。重要規(guī)范分庫分表跨分片事務必須以 GlobalTransactional 為入口僅使用 Transactional 會導致跨分片事務完全失效。5.0.3 注解組合使用規(guī)范生產標準分片分布式事務標準寫法入口方法加 GlobalTransactional分支業(yè)務方法加 Transactional形成「全局事務統(tǒng)籌本地事務兜底」的雙層事務架構。5.1 項目依賴5.1 項目依賴核心引入Sharding-JDBC分片依賴、SEATA事務依賴版本適配SpringCloud Alibaba生態(tài)。!-- sharding-jdbc 分庫分表核心依賴 -- dependency groupIdorg.apache.shardingsphere/groupId artifactIdsharding-jdbc-spring-boot-starter/artifactId version4.1.1/version /dependency !-- seata 分布式事務 -- dependency groupIdio.seata/groupId artifactIdseata-spring-boot-starter/artifactId version1.5.2/version /dependency5.2 數(shù)據庫準備模擬分庫場景創(chuàng)建2個分庫order_db_0、order_db_1每個庫包含訂單分片表t_order_0 ~ t_order_1所有分片庫必須初始化undo_log表。CREATE TABLE IF NOT EXISTS undo_log ( id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 自增主鍵, branch_id BIGINT(20) NOT NULL COMMENT 分支事務ID, xid VARCHAR(128) NOT NULL COMMENT 全局事務ID, context VARCHAR(128) NOT NULL COMMENT 上下文, rollback_info LONGBLOB NOT NULL COMMENT 回滾鏡像信息, log_status INT(11) NOT NULL COMMENT 0正常1已回滾, log_created DATETIME NOT NULL, log_modified DATETIME NOT NULL, PRIMARY KEY (id), UNIQUE KEY ux_undo_log (xid,branch_id) ) ENGINEInnoDB DEFAULT CHARSETutf8 COMMENTSEATA事務回滾日志表;5.3 核心差異化配置整合專屬與單獨使用差異對比SEATA、Sharding-JDBC單獨使用時無需特殊適配但二者整合場景存在數(shù)據源代理、事務托管沖突必須添加專屬差異化配置也是整合事務生效的核心關鍵僅列舉差異配置常規(guī)分片、SEATA基礎配置不再贅述。# SEATA Sharding 整合差異化專屬配置 spring: shardingsphere: # 核心差異1關閉Sharding原生事務避免與SEATA事務沖突 # 單獨用Sharding默認LOCAL整合SEATA必須改為NONE交由SEATA統(tǒng)一托管 transaction: type: NONE # 其余常規(guī)分片規(guī)則、數(shù)據源配置、SEATA注冊配置與單獨使用保持一致無需改動配套Java差異化配置唯一代碼差異單獨使用 Sharding/SEATA 無需手動代理數(shù)據源整合場景必須手動用 SEATA 數(shù)據源代理包裹 Sharding 數(shù)據源解決多層代理沖突否則跨分片事務完全不生效。Configuration public class SeataShardingConfig { Bean Primary public DataSource dataSource(ShardingDataSource shardingDataSource) { // 整合專屬差異SEATA嵌套代理Sharding數(shù)據源 return new DataSourceProxy(shardingDataSource); } }全局事務模式兜底差異生產環(huán)境統(tǒng)一兜底配置spring.shardingsphere.transaction.typeBASE適配SEATA AT模式禁止XA/LOCAL模式混用規(guī)避事務協(xié)議沖突。重點關閉Sharding自帶事務、適配SEATA事務代理保證分布式事務生效。spring: # 關閉sharding默認本地事務交給seata托管 shardingsphere: props: sql-show: true allow-range-query-without-sharding-key: true # 關閉sharding原生事務 transaction: type: NONE # 分庫分表規(guī)則配置 datasource: names: ds0,ds1 ds0: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/order_db_0?useSSLfalseserverTimezoneGMT%2B8 username: root password: 123456 ds1: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/order_db_1?useSSLfalseserverTimezoneGMT%2B8 username: root password: 123456 sharding: tables: t_order: actual-data-nodes: ds$-{0..1}.t_order_$-{0..1} database-strategy: inline: sharding-column: user_id algorithm-expression: ds$-{user_id % 2} table-strategy: inline: sharding-column: order_id algorithm-expression: t_order_$-{order_id % 2} # SEATA 分布式事務配置 seata: enabled: true tx-service-group: default_tx_group service: vgroup-mapping: default_tx_group: default registry: type: nacos nacos: server-addr: 127.0.0.1:8848 config: type: nacos nacos: server-addr: 127.0.0.1:8848手動注入SEATA代理數(shù)據源覆蓋Sharding默認數(shù)據源解決事務不生效、代理沖突核心問題。Configuration public class SeataShardingConfig { Bean Primary public DataSource dataSource(ShardingDataSource shardingDataSource) { // SEATA代理Sharding數(shù)據源實現(xiàn)分片事務管控 return new DataSourceProxy(shardingDataSource); } }5.5 業(yè)務實戰(zhàn)代碼跨分片分布式事務模擬一次下單跨分片寫入手動制造異常測試多分片事務一致性。Service public class OrderServiceImpl implements OrderService { Resource private OrderMapper orderMapper; // 開啟跨分片分布式事務 Override GlobalTransactional(rollbackFor Exception.class) public void createOrder(Order order) { // 1.插入訂單自動根據分片鍵路由至不同分庫分表 orderMapper.insert(order); // 2.模擬業(yè)務異常觸發(fā)全分片回滾 int i 1 / 0; } }5.6 效果驗證正常無異常所有分片數(shù)據寫入成功undo_log自動清除代碼拋出異常所有已寫入的分片數(shù)據全部回滾無任何臟數(shù)據殘留徹底解決原生Sharding-JDBC跨分片部分成功、部分失敗的事務問題。5.7 分片場景注解搭配高頻坑點匯總生產致命問題SEATA Sharding-JDBC 整合架構中注解使用不規(guī)范是跨分片事務失效、臟讀、回滾重試卡死、數(shù)據不一致的第一大成因。下面匯總生產 7 類最高頻、最隱蔽的注解搭配錯誤明確錯誤場景、故障原理與標準規(guī)范。5.7.1 坑點一只寫 GlobalTransactional不加 ShardingSphereTransactionType(BASE)錯誤場景跨多分庫、多分片業(yè)務僅使用 SEATA 全局事務注解未手動指定 Sharding 事務類型。故障原理Sharding-JDBC 默認自帶本地事務管控若未強制指定BASE適配 SEATA AT 模式分片底層會走原生本地事務邏輯??绶制霈F(xiàn)異常時Sharding 本地事務無法聯(lián)動 SEATA 全局事務部分分片本地提交成功、SEATA 全局回滾指令無法覆蓋分片數(shù)據最終導致分庫數(shù)據回滾失效、分片數(shù)據不一致。正確規(guī)范SEATA AT 整合分片場景統(tǒng)一配置spring.shardingsphere.transaction.typeBASE全局適配 SEATA 事務托管杜絕原生事務沖突。5.7.2 坑點二GlobalLock 缺少 Transactional / for update錯誤場景分片高并發(fā)讀寫場景僅使用 SEATA 全局鎖注解GlobalLock未搭配本地事務或行鎖。故障原理GlobalLock 僅控制全局分布式鎖不替代本地事務與數(shù)據庫行鎖。缺少本地事務包裹時數(shù)據庫語句自動提交、鎖瞬間釋放全局鎖約束失效。高并發(fā)下依然存在跨分片臟讀、數(shù)據覆蓋問題最終觸發(fā) SEATAundo 鏡像校驗失敗、事務無限重試卡死。正確規(guī)范GlobalLock 必須嵌套 Transactional 本地事務熱點數(shù)據查詢更新搭配 for update 行鎖雙重杜絕臟讀。5.7.3 坑點三分片場景 GlobalLock lockKey 未攜帶分片字段錯誤場景跨庫分表場景全局鎖 lockKey 僅使用業(yè)務ID未攜帶分片字段user_id/分庫標識。故障原理Sharding 分片數(shù)據分散在不同庫、不同表中若鎖 Key 不攜帶分片字段鎖作用域會錯亂。不同分片的不同業(yè)務數(shù)據會共用同一把鎖或本該互斥的分片數(shù)據無法加鎖跨分片互相臟讀、數(shù)據覆蓋引發(fā)回滾校驗失敗。正確規(guī)范分片場景 lockKey 必須包含「分片鍵唯一業(yè)務ID」保證鎖粒度精準綁定單分片單行數(shù)據隔離跨分片并發(fā)讀寫。5.7.4 坑點四DDL 語句放在 GlobalTransactional 方法內錯誤場景全局事務方法中執(zhí)行建表、改表、加索引等 DDL 語句。故障原理MySQL 對 DDL 語句會強制觸發(fā)自動提交本地事務會直接打斷 SEATA 一階段鏡像生成流程導致當前分支 undo 日志丟失、無回滾快照。全局事務異常時SEATA 無數(shù)據可還原事務回滾徹底失效產生永久性分片臟數(shù)據。正確規(guī)范所有 DDL 語句禁止納入 SEATA 全局事務單獨執(zhí)行、避開事務切面。5.7.5 坑點五遺漏內層 Transactional 本地事務錯誤場景外層僅添加 GlobalTransactional內層分片業(yè)務方法無任何本地事務注解。故障原理SEATA 分支 RM 生成 undo_log 鏡像的前置條件是本地事務上下文生效。內層無 Transactional 時分片 SQL 自動提交、無法被 SEATA 切面攔截RM 分支無 undo 快照生成。二階段全局回滾時無鏡像可還原直接回滾失敗。正確規(guī)范嚴格遵循「外層 GlobalTransactional 內層分片業(yè)務 Transactional」雙層事務規(guī)范。5.7.6 坑點六混用 XA 與 BASE 事務類型錯誤場景項目同時存在 XA、BASE 兩種事務模式或分片配置與 SEATA 模式不匹配。故障原理XA 強一致性事務與 BASE 最終一致性事務的分支注冊、日志機制、鎖機制完全不兼容。混用后事務協(xié)議沖突SEATA TC 無法正常識別、注冊分片分支事務導致全局事務創(chuàng)建失敗、分片事務不生效、提交回滾異常。正確規(guī)范一個項目統(tǒng)一一種事務模式分片整合 SEATA AT 必須固定 typeBASE禁止多模式混用。5.7.7 坑點七單純依賴 GlobalTransactional完全放棄 Sharding 事務管控錯誤場景認為開啟 SEATA 全局事務即可隨意關閉、修改 Sharding 事務配置。故障原理Sharding-JDBC 承擔多分片 SQL 路由、多數(shù)據源調度若完全取消 Sharding 事務適配分片多數(shù)據源執(zhí)行時序錯亂SEATA 無法統(tǒng)一接管多分片分支出現(xiàn)部分分片未納入全局事務、回滾遺漏的問題。正確規(guī)范必須配置spring.shardingsphere.transaction.typeBASE適配 SEATA不關閉分片事務適配能力實現(xiàn)框架分層托管。六、生產踩坑與解決方案6.1 坑點1整合后分布式事務不生效原因Sharding-JDBC原生事務與SEATA數(shù)據源代理沖突未關閉Sharding默認事務。解決配置spring.shardingsphere.transaction.typeNONE強制交給SEATA托管。6.2 坑點2跨分片回滾觸發(fā)data validation failed原因高并發(fā)下多分片數(shù)據被外部線程篡改鏡像校驗失敗。解決熱點分片數(shù)據增加分布式鎖、禁止并發(fā)修改核心業(yè)務拆分小事務。6.3 坑點3多分片大事務超時回滾失敗原因跨多庫多分片事務耗時過長TC強制終止分片狀態(tài)割裂。解決禁止大事務、拆分分片業(yè)務調優(yōu)SEATA超時時間增加定時對賬兜底。七、全文總結Sharding-JDBC 解決了海量數(shù)據的存儲擴容、讀寫性能問題但缺失分布式事務能力SEATA AT 模式解決了跨分片數(shù)據一致性問題。兩者結合是目前互聯(lián)網海量數(shù)據高并發(fā)項目的標準生產架構。該方案具備零侵入、高性能、易擴展的優(yōu)勢適配絕大多數(shù)電商、流水、賬單、用戶數(shù)據業(yè)務但存在AT模式天生的隔離性缺陷金融級強一致場景需要升級為Sharding SEATA TCC模式。同時生產必須遵循小事務規(guī)范、配合兜底對賬保證分片事務百分百可靠。