概要
seata 是alibaba 出的一款分布式事務管理器,他有侵入性小,實現簡單等特點。我們能夠使用seata 實現分布式事務管理,
是微服務必備的組件。他可以實現在微服務之間的事務管理,也可以實現多個數據源的事務管理。
seata 在阿里內部,和眾多的公司都有應用,因此我們可以放心的使用它。
實現的基本原理
SEATA 實現了幾種事務模式,我們使用AT模式,他使用起來簡單,代碼侵入性小。
下圖就是AT的事務過程。
TM是事務管理者
RM 資源管理者,可以認為是數據庫。
TC 是事務協調者,就是SEATA 服務
TM 向 TC 申請開啟一個全局事務,全局事務創建成功並生成一個全局唯一的 XID。
XID 在微服務調用鏈路的上下文中傳播。
RM 向 TC 注冊分支事務,將其納入 XID 對應全局事務的管轄。
TM 向 TC 發起針對 XID 的全局提交或回滾決議。
TC 調度 XID 下管轄的全部分支事務完成提交或回滾請求。
實現方式
配置SEATA
引入相關JAR包
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-seata</artifactId> <version>2.1.1.RELEASE</version> <scope>compile</scope> <exclusions> <exclusion> <groupId>io.seata</groupId> <artifactId>seata-all</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.seata</groupId> <artifactId>seata-all</artifactId> <version>1.2.0</version> </dependency>
在resources 下增加文件 registry.conf,我的實現為使用nacos作為配置和注冊中心
文件內容如下:
registry { type = "nacos" nacos { application = "seata-server" serverAddr = "192.168.31.10:8848" #namespace = "public" group = "DEFAULT_GROUP" #cluster = "default" #username = "nacos" #password = "nacos" } } config { type = "nacos" nacos { serverAddr = "192.168.31.10:8848" namespace = "" group = "SEATA_GROUP" cluster = "default" username = "nacos" password = "nacos" } }
第一段是注冊中心的配置,第二段為配置中心的配置,配置實際上是放到nacos 下的。
配置文件路徑:
https://gitee.com/seata-io/seata/blob/develop/script/config-center/config.txt
可以把這個下下來,然后使用命令將這個配置,提交到 nacos,命令的路徑為:
https://gitee.com/seata-io/seata/tree/develop/script/config-center/nacos
我們可以如下執行命令:
nacos-config.sh -h nacos的IP -p nacos端口 -u nacos用戶名 -w nacos密碼
這個配置需要修改的地方:
service.vgroupMapping.bpm_tx_group=default service.vgroupMapping.form_tx_group=default service.vgroupMapping.portal_tx_group=default service.vgroupMapping.user_tx_group=default service.vgroupMapping.system_tx_group=default
這個配置 為
service.vgroupMapping + 應用的配置 =default
這個default 對應上面的配置
事務數據存儲到數據庫
修改 數據庫的配置,我們將配置導入到nacos 。
同時,需要將剛剛的配置文件 registry.conf 拷貝到 seata 目錄下
配置好后需要先啟動 nacos,在啟動 seata
nohup ./seata-server.sh -p 8888 -h 192.168.31.10 &
seata 數據庫腳本:
https://gitee.com/seata-io/seata/blob/develop/script/server/db/mysql.sql
這樣 事務配置就處理好了。
我們需要在微服務的每個數據庫中增加 UNDO_LOG表。
CREATE TABLE IF NOT EXISTS `undo_log` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT 'increment id', `branch_id` BIGINT(20) NOT NULL COMMENT 'branch transaction id', `xid` VARCHAR(100) NOT NULL COMMENT 'global transaction id', `context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization', `rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info', `log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status', `log_created` DATETIME NOT NULL COMMENT 'create datetime', `log_modified` DATETIME NOT NULL COMMENT 'modify datetime', PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`) ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';
這個需要和微服務數據庫在一起。
代碼實現
@Bean("dataSource") @ConfigurationProperties(prefix = "spring.datasource") public DruidDataSource druidDataSource() { return new DruidDataSource(); } @Bean("dataSourceProxy") public DataSourceProxy dataSourceProxy(@Qualifier("dataSource")DataSource dataSource) { DataSourceProxy proxy=new DataSourceProxy(dataSource); return proxy; }
實際上我們在代碼中使用的是 DataSourceProxy 代理過的數據源。
測試如下:
在測試時,我們可以發現,通過RootContext 取得Xid。