引言
隨著業(yè)務和數(shù)據(jù)量的增加臭蚁,應用采用微服務部署日益增多簿废,但是絕大多數(shù)微服務架構(gòu)應用也還是采用的單數(shù)據(jù)庫模式为居,即便是大多數(shù)讀寫分離枯途,本質(zhì)也還是單數(shù)據(jù)庫忌怎,隨著業(yè)務量和數(shù)據(jù)量增多,數(shù)據(jù)庫讀寫效率急劇下降酪夷,此時就需要對數(shù)據(jù)庫進行維度拆分榴啸,如水平拆分(分表)、垂直拆分(分庫)
本文討論的情況為水平拆分與垂直拆分晚岭,以及遇到的各種集成問題
版本
ShardingSphere:4.0.0-RC2-SNAPSHOT
Seata:0.5.1
Mybatis-Plus:2.3.1
DruidDataSource:1.1.10
ShardingSphere目前對應Dev未發(fā)布版本
規(guī)則
提前將項目對應sql目錄文件導入數(shù)據(jù)庫鸥印,undo_log表為Seata用于回滾的表
其余t_order_0、t_order_1坦报、t_order_item_0库说、t_order_item_1為ShardingSphere對應的分表,注意:一定要提前創(chuàng)建好分庫分表片择,因為ShardingSphere內(nèi)部是需要提前進行分庫分表掃描并加入ShardingSphere對應的DataSourceMap
簡介
Seata AT 事務模型包含 TM(事務管理器)潜的,RM(資源管理器),TC(事務協(xié)調(diào)器)字管。
TC為seata-server啰挪,可以理解為單獨部署的服務器,TM/RM 通過RPC與TC進行交互
ShardingSphere 分布式事務
ShardingSphere SPI供用戶擴展XA強一致性事務或者是Base柔性事務嘲叔,而Seata AT作為一種Base柔性事務的一種實現(xiàn)亡呵,本文著重分析和使用Seata
整合SeataAT分析過程
從ShardingSphere 官方圖像顯示,Seata與ShardingSphere 框架都是對DataSource 進行封裝和處理硫戈,所以要將Seata事務融入到ShardingSphere 框架中使用锰什,就需要將Seata框架中DataSourceProxy包裝給ShardingSphere 框架的ShardingTransactionManager接口。不好理解丁逝?那咱們通過代碼分析
從上圖可知SeataATShardingTransactionManager實現(xiàn)了ShardingTransactionManager汁胆,這是一個SPI擴展接口,將SeataAT事務融入到ShardingSphere 框架中
通過查看initSeataRPCClient接口可知
對Seata的TM霜幼、RM進行初始化沦泌,以上簡要概述了ShardingSphere 使用SeataAT事務的流程,下面結(jié)合Springboot來具體分析集成各個框架的流程
分析1:ShardingSphere 創(chuàng)建DataSource
在sharding-jdbc-spring-boot-starter工程中SpringBootConfiguration會自動裝配參數(shù)
通過代碼分析辛掠,啟動之后通過遍歷配置的names字段創(chuàng)建DataSource,其中return DataSourceUtil.getDataSource(dataSourceProps.get("type").toString(), dataSourceProps);通過用戶配置的連接池類型進行初始化,因為ShardingSphere默認使用的HikariDataSource萝衩,而項目需要使用DruidDataSource回挽,所以繼續(xù)分析創(chuàng)建DataSource的過程
通過代碼得知,ShardingSphere框架通過反射猩谊,將type字段同級的參數(shù)一并傳入進行反射調(diào)用千劈,所以我們就需要將DruidDataSource所需參數(shù)放置到type字段同級
這樣就完成了使用DruidDataSource?答案是NO牌捷,細心的同學可能會在啟動日志中發(fā)現(xiàn)輸出了Init DruidDataSource墙牌,通過繼續(xù)分析發(fā)現(xiàn)
DruidDataSource自動創(chuàng)建了DataSource,我們的期望是DataSource由ShardingSphere進行創(chuàng)建暗甥,所以我們需要在@SpringBootApplication中排除DruidDataSourceAutoConfigure,至此ShardingSphere創(chuàng)建DataSource的過程完成
分析2:ShardingSphere使用SeataAT事務
通過上訴分析我們已經(jīng)得知ShardingSphere已經(jīng)創(chuàng)建好了各個DataSource并將其放入dataSourceMap集合中喜滨,通過Seata官網(wǎng)可知,需要使用Seata事務撤防,需要使用Seata提供的DataSourceProxy類虽风,繼續(xù)通過源碼分析
ShardingSphere內(nèi)部通過SPI擴展,將ShardingTransactionManager接口暴露寄月,在ShardingSphere創(chuàng)建完DataSource之后辜膝,緊接著通過擴展ShardingTransactionManager接口,將dataSourceMap集合中的各個DataSource代理給DataSourceProxy漾肮,至此SeataAT已經(jīng)融入ShardingSphere,但是現(xiàn)在使用Seata的@GlobalTransactional是無效的厂抖,下文會繼續(xù)分析
分析3:集成Mybatis-Plus/Mybatis
Mybatis-Plus作為Mybatis的一種增強,引入Mybatis-Plus之后并配置參數(shù)
一切看起來是那么的輕松克懊,啟動項目...不出意外將出現(xiàn)以下信息
為什么,為什么忱辅、為什么會這樣.我太難了...
話不多說,繼續(xù)分析原因,因為我們使用Mybatis-Plus保檐,默認會引入Mybatis依賴庫耕蝉,然后DataSourceAutoConfiguration會自動加載,DataSourceAutoConfiguration會查找spring->datasource->url字段夜只,因為我們用的ShardingSphere垒在,并未配置這樣的參數(shù),知道原因了那就繼續(xù)在@SpringBootApplication中排除DataSourceAutoConfiguration
繼續(xù)啟動項目......不出意外出現(xiàn)以下信息
錯誤提示沒有發(fā)現(xiàn)sqlSessionFactory扔亥,因為我們使用Mybatis-Plus场躯,正常情況下因由Mybatis-Plus進行sqlSessionFactory的創(chuàng)建,繼續(xù)查看Mybatis-Plus源碼
打個斷點調(diào)試一波旅挤,發(fā)現(xiàn)確實沒有進入踢关,這又是為什么?查看MybatisPlusAutoConfiguration上面的注解發(fā)現(xiàn)粘茄,因為我們已經(jīng)排除了DataSourceAutoConfiguration了签舞,知道原因了秕脓,就是這個MybatisPlusAutoConfiguration沒生效,怎么辦儒搭?
自己重寫一份MybatisPlusAutoConfiguration到項目里面吧吠架,在SpringBootApplication中直接排除MybatisPlusAutoConfiguration
至此Mybatis-Plus集成完畢
分析4:Seata 注解@GlobalTransactional
在上文中說道ShardingSphere使用SeataAT事務,但是官方例子是Jdbc直連搂鲫,不符合SpringBoot集成特點傍药,所以本段落主要分析和如何使用@GlobalTransactional注解
如果我們使用Seata官方例子不難發(fā)現(xiàn),我們直接使用@GlobalTransactional注解是很方便的魂仍,也無需關(guān)心@GlobalTransactional 內(nèi)部是如何實現(xiàn)的拐辽,但是當我們集成了ShardingSphere之后,我們按照Seata官方例子那樣直接在我們的業(yè)務Service上面使用@GlobalTransactional注解擦酌,會發(fā)現(xiàn)這個注解是無效的俱诸。這又是為什么?查看下源碼
GlobalTransactionScanner實現(xiàn)AbstractAutoProxyCreator仑氛,然后根據(jù)wrapIfNecessary判斷具體的Bean實體是否需要進行Aop包裝/代理/增強,包裝的條件為是否存在GlobalTransactional注解
回過頭我們發(fā)現(xiàn)ShardingSphere封裝的SeataATShardingTransactionManager類只是初始化了TMClient乙埃、RMClient。并沒有對Seata的@GlobalTransactional注解進行處理
知道流程之后我們不難發(fā)現(xiàn)@GlobalTransactional注解的具體攔截實現(xiàn)類是GlobalTransactionalInterceptor锯岖。查看源碼
發(fā)現(xiàn)實現(xiàn)Aop的MethodInterceptor
既然已經(jīng)分析到了這里介袜,那么方法自然而然就有了
方案1:重寫GlobalTransactionScanner類,然后通過@Bean注入,把里面的TMClient出吹、RMClient這些剔除,因為TMClient遇伞、RMClient已經(jīng)在ShardingSphere的SeataATShardingTransactionManager類里面進行初始化了,此方案為最佳推薦方案捶牢,因為GlobalTransactionScanner內(nèi)部做了代理判斷
方案2:直接通過AOP進行處理鸠珠,簡單粗暴,但是如果是線上不推薦該方案,因為沒有GlobalTransactionScanner處理的全面
至此Springboot集成ShardingSphere+Seata+Mybatis-Plus+DruidDataSource完畢秋麸,若有錯誤地方歡迎指出,后續(xù)文章將繼續(xù)分析和使用Nacos渐排、Dubbo
例子已整合到Seata官方Demo中: https://github.com/seata/seata-samples/tree/master/springboot-shardingsphere-seata