一、Seata-AT模式
AT模式下,客户端只需要关注自身的业务SQL,Seata框架会自动生成事务的二阶段提交和回滚操作。Seata-AT模式官网
(一)运行机制
AT模式遵循之前介绍2PC协议,分两个阶段进行分布式事务的管理
- 一阶段:准备阶段,分支事务获取全局锁,执行sql,执行完毕后释放全局锁
- 二阶段:提交阶段,根据分支事务的执行情况判断回滚还是提交,若是回滚,则已执行的分支事物会开辟一个新事务,执行回滚操作。
(二)AT模式时序图
commit时序图
rollback时序图
(三)实际操作
1.创建服务8001,8002
引入pom依赖
<!-- nacos依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- seata -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<!-- mysql-connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<!-- openFeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
application.properties文件
server:
port: 8001
spring:
application:
name: seata-order
cloud:
cloud:
discovery:
server-addr: localhost:8848
alibaba:
seata:
# 事务分组:mygroup
tx-service-group: mygroup
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db1?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
management:
endpoints:
web:
exposure:
include: '*'
seata:
tx-service-group: mygroup # 事务组名称,要和服务端对应
service:
vgroup-mapping:
mygroup: default # key是事务组名称 value要和服务端的机房名称保持一致
2.准备数据
(1)stock库存表
CREATE TABLE `stock` (
`product_id` int(11) NOT NULL AUTO_INCREMENT,
`count` int(11) DEFAULT NULL,
`money` int(255) DEFAULT NULL,
PRIMARY KEY (`product_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
(2)order订单表
CREATE TABLE `order` (
`product_id` int(11) NOT NULL,
`count` int(11) DEFAULT NULL,
PRIMARY KEY (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
(3)undo_log日志表
undo_log日志表可以去官网->开发者指南->各事务模式->Seata AT 模式,网址为:
sql语句在页面底部
CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
`ext` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
3.Client服务端代码编写
TM(order8001)事务管理者Controller
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private FeignService feignService;
@GetMapping("create")
@GlobalTransactional
/**
* 访问次接口的所有请求,都会被Seata管理分布式事务,
* 也就是TM(开始事务的服务器)
*/
public String create(){
feignService.decrease();
orderService.create();
return "SUCCESS";
}
}
TM(order8001)Service
@FeignClient("seata-stock")
@Service
public interface FeignService {
@GetMapping("stock/decrease")
public String decrease();
}
@Service
public class OrderServiceImpl implements OrderService {
@Resource
private OrderMapper orderMapper;
@Override
public void create() {
orderMapper.create();
}
}
RM事务参与者(stock8002)的Controller
@RestController
@RequestMapping("stock")
public class StockController {
@Autowired
private StockService stockService;
@GetMapping("decrease")
public String decrease(){
stockService.decrease();
return "减少库存";
}
}
此时,参与者会在undo_log中记载镜像,一旦有一个参与者报错,会全部使用日志的信息回滚数据,使所有库的数据为事务开始前的样子。
二、Seata-XA模式
(一)什么是XA协议
XA协议是一个用于解决分布式领域问题的协议,描述了全局事务和分支事务之间的接口,利用数据库本身的ACID特点,使RPC环境下依然能够实现事务,现在的许多数据库,例如Mysql,Oracle都支持XA协议。
1.DTP角色(DTP,Distributed Transaction Processing)
- AP:应用程序,即使用分布式事务的应用程序
- RM:资源管理器,事务参与者(可以简单理解为Mysql数据源)
- TM:事务管理器。
2.XA案例
注意,这里的回滚是数据库直接回滚,RM只会开启一个事务,并且根据TM的通讯知道需不需要回滚事务,而不是利用日志中的信息重新开启一个事务回滚。
XA模式的痛点:如果其中一个RM突然挂掉了,那么TM一直处于阻塞状态,锁不能释放,那么这个全局事务会一直无法结束,这是XA模式的一个问题。
(二)Seata的分布式事务模式
1.Seata事务框架
同一个事务ID代表该两个分支事务处于同一个全局事务中。
2.Seata分布式事务的两个阶段
- 执行阶段 :执行分支事务,并保证执行结果满足是 可回滚的(Rollbackable) 和 持久化的(Durable)。
- 完成阶段: 根据执行结果形成的决议,应用通过 TM 发出的全局提交或回滚的请求给 TC,TC 命令 RM 驱动 分支事务 进行 Commit 或 Rollback。
(三)Seata的XA模式和AT模式的对比
1.AT模式
- 执行阶段:
- 可回滚:记录回滚日志
- 持久化:本地事务直接提交
- 完成阶段:
- 分支提交:删除回滚日志记录
- 分支回滚:依据回滚日志进行反向补偿更新
2.XA模式
- 执行阶段:
- 可回滚:数据库支持XA协议,仅执行Prepare,事务并未提交
- 持久化:数据库支持XA协议,会达到一致性状态
- 完成阶段:
- 分支提交:执行 XA 分支的 commit
- 分支回滚:执行 XA 分支的 rollback
3.对比总结
AT模式存在软状态,并且如果网络通信较差,软状态持续的时间会比较长,因此,有可能出现数据脏读,但是XA模式在全局事务Prepare以前都不会提交,因此不会存在脏读问题。
此外,AT模式支持的是最终一致性,而XA模式是强一致性的,不需要用任何日志来记录镜像,不存在中间状态。
(四)Seata-XA模式的优点和缺点
优点:
- 无业务请入:不会给应用设计和开发带来额外负担;
- 数据库的支持广泛:不需要额外的适配,适用性强
- 多语言支持:Mysql、Oracle等
- 方便系统迁移:如果一个老应用需要迁移到Seata,会比较方便。
缺点:
如果在全局事务没有提交的时候,某一个RM挂掉了, 就可能会导致阻塞死锁的问题。
(五)XA模式使用示例
三、Seata-TCC模式
(一)定义
Try-Confirm-Cancel模式,其中:
- Try:对业务资源检查并预留,即Prepare操作。
- Confirm:对业务进行提交,即Commit操作,Try成功后就会Confirm。
- Cancel:回滚操作,Try失败以后,对Try预留的资源进行释放。
优点:
TCC完全不依赖数据库,能够实现跨数据局,跨应用资源管理,对不同的数据访问实现了院子操作,可以解决复杂场景下的分布式事务问题。
缺点:
TCC模式是一种侵入性强的业务模式,需要各个业务系统自行实现,设计相对比较复杂。
(二)示意图
1.TCC模式示意图
2.Seata-TCC模式示意图
TCC和AT模式的区别在于,AT模式的日志是统一管理的,会生成镜像,不需要自定义接口,而TCC是倾入性的,需要自己定义try,confirm和cancle逻辑,根据业务的情况调用对应的接口。
所谓 TCC 模式,是指支持把 自定义 的分支事务纳入到全局事务的管理中。
(三)使用示例
四、Seata-Saga模式
(一)定义
是一种长事务的解决方案,业务中每个参与者都会提交本地事务,当出现一个参与者的失败案例则反向补偿
前面的事务参与者。
(二)适用场景
Saga模式提供了异构系统的事务统一处理模型。所有的子业务都不再直接参与整体事务的处理(只负责本地事务的处理),而是全部交由了最终调用端来负责实现,而在进行总业务逻辑处理时,在某一个子业务出现问题时,则自动补偿全面已经成功的其他参与者,这样一阶段的正向服务调用和二阶段的服务补偿处理全部由总业务开发实现。
(三)业务流程图
(四)使用
Saga模式是基于状态机引擎实现的,但是具体的我也不懂,用的时候可以去官网康康官方网站Saga模式使用文档