概要
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。