介绍
阿里巴巴的 Seata(Service Aligned Transaction Alternative)是一个开源的分布式事务解决方案,旨在解决微服务架构中跨服务、跨数据库的事务一致性问题。它可以帮助开发者管理分布式系统中的全局事务,确保在多个服务之间的事务一致性。
引入依赖
<!--seata-->
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.6.1</version>
</dependency>
配置
每个服务中引入
seata:
registry: #注册中心的配置
type: nacos #注册中心类型为nacos
nacos:
server-addr: 172.23.4.128:8848 #服务注册地址
namespace: "" #命名空间
group: DEFAULT_GROUP #默认DEFAULT_GROUP
application: seata-server #服务名称
tx-service-group: test #事务组名称
service:
vgroup-mapping: #事务与组的映射关系
test: "default"
XA模式
-
阶段1:预提交阶段
参与事务的各个资源(如数据库)会锁定事务需要的资源并准备执行。此时,Seata 会询问每个参与者是否可以提交,参与者进行本地准备并响应是否可以提交。 -
阶段2:提交或回滚阶段
如果所有参与者都可以提交(即没有遇到错误),Seata 会发出全局提交请求;否则,发出回滚请求。 -
事务一致性:采用 XA 协议保证跨多个资源的事务的一致性,确保事务在分布式环境中能实现原子性操作。
-
资源协调:Seata 作为事务协调者,协调所有参与资源的提交与回滚,确保最终一致性。
-
回滚与补偿:若事务失败,Seata 会确保通过回滚来恢复到事务开始前的状态。
-
支持的数据库:Seata XA模式支持通过 XA 协议的数据库,常见的如 MySQL、Oracle 等,前提是这些数据库支持 XA 协议。
缺点
性能开销:XA 模式的两阶段提交协议需要多次通信和锁定资源,可能会导致性能下降,特别是在大规模、高并发的场景中。
支持的资源类型较少:XA 协议主要支持数据库等传统资源,对于一些新型的分布式资源(如消息队列、缓存等)可能支持不够好,或者实现较复杂。
开启XA模式
在全局配置中添加
seata:
data-source-proxy-mode: XA #开启XA模式
开启事务
@GetMapping("/pay")
@GlobalTransactional
public SaResult pay(){
//假设余额扣减
String userId=StpUtil.getLoginIdAsString();
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(User::getId, userId) // 根据用户ID进行查询
.setSql("play_num = play_num - 1"); // 扣减play_number
userService.update(updateWrapper);
if(true){ //模拟报错
int i = 1 / 0;
}
goodsClient.delete();
//删除
return SaResult.ok();
}
相关的服务也需要 @Transient
@DeleteMapping("/delete")
@Transient
public Boolean delete(){return goodsService.removeById(1);}
这里进行了两次SQL,一次是自己的user库,一个是远程调用的微服务。如果其中一个报错了都会保证数据的一致性。
AT模式
主推的是AT模式,AT模式同样是分阶段提交的事务模型,缺弥补了XA模型中资源锁定周期过长的缺陷。AT模式会导致几毫秒的数据不一致因为立马提交了SQL语句。
运行步骤:
阶段一:注册事务分支->记录undo-log(数据快照) ->执行业务SQL并提交
阶段二:删除undo-log(数据快照)
因此如果使用AT模式需要给每一个微服务都添加undo-log表。
相关文档:https://seata.apache.org/zh-cn/docs/v1.5/overview/what-is-seata
创建undo-log
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,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
修改AT模式
data-source-proxy-mode: AT
去除默认就是AT模式
seata:
data-source-proxy-mode: AT
SQL日志
事务开始时会先记录快照如果报错就会回滚。
如何选择模式
如果对业务一致性高的话选择XA模式会对数据库进行锁表,对于性能要求选择AT模式,AT模式会导致几毫秒的数据不一致因为立马提交了SQL语句。