十二、集成分布式事务组件Seata

什么是Seata

网址:seata.io

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

 seata术语

TC (Transaction Coordinator) - 事务协调者

维护全局和分支事务的状态,驱动全局事务提交或回滚。相当于下载的seata

TM (Transaction Manager) - 事务管理器

定义全局事务的范围:开始全局事务、提交或回滚全局事务。相当于应用(business、member)

RM (Resource Manager) - 资源管理器

管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。相当于数据库。

Seata分布式事务的原理

 正常情况下,如果某一步失败了,需要做补偿来还原。补偿交给seata来做。

Seata分布式事务的四种模式

  • AT模式,默认,简单,需要增加undo_log表,生成反向SQL,性能高。(对于insert,就反向生成delete). 回滚后,原来没数据的, 现在还是没有数据.
  • TCC模式,try confirm/cancel,三个阶段的代码都得自己实现,Seata只负责调度。confirm和cancel只能实现一次。对业务代码侵入性较强,必要时可能要修改数据库。
  • SAGA模式,长事务解决方案,需要程序员自己编写两阶段代码(AT模式不需要写第二阶段)。基于状态机实现,需要一个JSON文件,可异步执行。
  • XA模式,XA协议是由X/Open组织提出的分布式事务处理规范,基于数据库的XA协议来实现2PC又称为XA方案,适用于强一致性的场景,比如金融、银行等。

Seata的实际使用

哪一个功能需要seata

选中座位后事务处理:
座位表修改售卖情况sell;
余票详情表修改余票;
为会员增加购票记录
更新确认订单为成功

橙色部分需要调用business的数据库,黑色的调用member的数据库。

回滚只能回滚本端的,不能回滚远端调用的。

首先要把ticket表中的col字段更改为seat_col字段,因为col是关键字,seata的AT模式会自动生成反向sql,且没有反引号' ',所以要求表里不能有关键字。

集成seata

创建undo_log表

 1 CREATE TABLE `undo_log` (
 2                             `id` bigint(20) NOT NULL AUTO_INCREMENT,
 3                             `branch_id` bigint(20) NOT NULL,
 4                             `xid` varchar(100) NOT NULL,
 5                             `context` varchar(128) NOT NULL,
 6                             `rollback_info` longblob NOT NULL,
 7                             `log_status` int(11) NOT NULL,
 8                             `log_created` datetime NOT NULL,
 9                             `log_modified` datetime NOT NULL,
10                             `ext` varchar(100) DEFAULT NULL,
11                             PRIMARY KEY (`id`),
12                             UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
13 ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

下载的seata直接可以解压运行。

通用配置引入依赖

1         <dependency>
2             <groupId>com.alibaba.cloud</groupId>
3             <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
4         </dependency>

配置(可以不写配置,因为有默认值)。

 1 seata:
 2   # 事务组名称
 3   tx-service-group: train-group
 4   # 事务组和seata集群做关联
 5   service:
 6     vgroup-mapping:
 7       train-group: default
 8     grouplist:
 9       # 事务组对应的机器
10       default: 127.0.0.1:8091

正常注解为@TranSaction,分布式事务注解@GlobalTranSaction

处于同一分布式事务的id   RootContext.getXID() 应该相同。

统一异常处理中

 1 @ExceptionHandler(value = Exception.class)
 2     @ResponseBody
 3     public CommonResp exceptionHandler(Exception e) throws Exception {
 4         LOG.info("seata全局事务ID: {}", RootContext.getXID());
 5         // 如果是在一次全局事务里出异常了,就不要包装返回值,将异常抛给调用方,让调用方回滚事务
 6         if (StrUtil.isNotBlank(RootContext.getXID())) {
 7             throw e;
 8         }
 9         CommonResp commonResp = new CommonResp();
10         LOG.error("系统异常:", e);
11         commonResp.setSuccess(false);
12         commonResp.setMessage("系统出现异常,请联系管理员");
13         //commonResp.setMessage(e.getMessage());
14         return commonResp;
15     }

上面如果不加if判断的话,member出现异常时,虽然commonResp.success=false,但是接口返回码是200,business会认为调用是成功的。

步骤!!!

1、增加一个undo_log表,格式固定,所有需要分布式事务的都需要添加

2、引入依赖并配置

3、@GlobalTransactional 开启事务

案例:两个人买一张票

Seata Server配置Nacos

 

客户端和配置中心整合

 1 seata:
 2   # seata注册中心
 3   registry:
 4     type: nacos
 5     nacos:
 6       application: seata-server
 7       server-addr: 127.0.0.1:8848
 8       group: SEATA_GROUP
 9       namespace: train
10       username: nacos
11       password: nacos
12   # seata配置中心
13   config:
14     type: nacos
15     nacos:
16       server-addr: 127.0.0.1:8848
17       group: SEATA_GROUP
18       namespace: train
19       data-id: seataServer.properties
20       username: nacos
21       password: nacos
22   # 事务组名称,必须在nacos中有配置过:service.vgroupMapping.train-group=default
23   tx-service-group: train-group
24     # 事务组和seata集群做关联
25     #service:
26     # vgroup-mapping:
27     #  test-group: default
28     # seata集群对应的机器
29     #grouplist:
30   # default: 127.0.0.1:8091
31 # 以下是nacos中的seataServer.properties的相关配置
32 # 和微服务模块的seata.tx-service-group保持一致

异常三次回滚

 步骤:每个事务一开始往global_table插入一条数据,多少个数据库操作就写多少条数据到branch_table。事务结束清空branch,回滚就读branch,生成反向sql,结束也要清空branch。

seata事务只支持INSERT、UPDATE、DELETE三类DML语法的部分功能。

使用限制:

  • 不支持SQL嵌套
  • 不支持多表复杂SQL
  • 不支持存储过程、触发器
  • 部分数据库不支持批量更新

 

posted on 2023-05-26 22:04  夏雪冬蝉  阅读(168)  评论(0编辑  收藏  举报