Appearance
1、什么是分布式事务
首先理解一下,为什么会用到分布式事务。
在分布式服务中,服务A中通过feign来调用服务B的方法,但是服务B的方法并不归属于服务A的事务体系中,因此如果此时服务B报错,并不会导致已经执行了的服务A的操作回退。
想要让服务A回退,那么就要让服务B纳入到服务A的事务体系中,也就是两者是同一个事务ID。这就是我们的分布式事务,它可以跨越服务来实现事务。
想要实现分布式事务,我们有多种方式,可以通过像redis这样的中间件来实现。
但也可以用到我们今天介绍的seata组件来实现。甚至发展至今,一般我们谈到分布式事务,基本上seata已经成了我们的不二选择。
2、Seata 是什么
Seata 是一款分布式事务解决方案,为微服务架构提供了强一致性的分布式事务支持。提供了全局事务管理和本地事务协调的功能,可以用于确保多个微服务之间的事务操作的一致性;提供了 AT、TCC、SAGA和XA等几种事务模式。
常见的两种分布式事务模型:AT 模型(基于 TCC,Try-Confirm-Cancel)和 TCC 模型(基于两阶段提交)。
AT模型
默认使用的是 AT模式
- 在业务表所在的数据库中创建一个名为undo_log的表,用于记录回滚SQL,即与执行SQL相反的SQL(例如,执行insert则对应delete)。
- 当业务表执行操作时,Seata会解析执行的SQL,生成回滚SQL并存储到undo_log表中。
- 在本地事务提交前,向Seata服务端注册分支,申请业务表中对应数据行的全局锁,阻止其他事务对该数据进行更新操作。
- 本地事务提交时,业务数据的更新和生成的undo log一起提交。
- 将本地事务执行结果报告给Seata服务端,多个服务的本地事务使用相同的事务ID和分支ID记录在Seata服务端。
- 如果某个本地事务发生错误,Seata服务端发起对应分支的回滚请求。
- 同时开启本地事务,通过事务ID和分支ID查询undo_log表,执行回滚SQL,并将执行结果报告给Seata服务端。
- 如果没有错误发生,Seata服务端会在对应分支上发起请求,异步批量删除undo_log表中的记录。
总体来说,Seata服务端记录了所有本地事务,同时在每个库中记录了 undo log。
当发生错误时,通过事务ID和分支ID找到同一组的所有本地事务,利用记录的undo log统一回退数据。
3、使用 Seata 的基本步骤
seata分为服务端(TC)和客户端(TM,RM),
客户端通过引入jar包来使用。服务端需要我们单独安装。
- TC(Transaction Coordinator):事务协调器,维护全局事务的运行状态,协调和落实全局事务的回滚提交
- TM(Transaction Manager):控制全局事务的边界,负责开启一个全局事务,并最终发起全局事务提交或回滚的决议
- RM(Resource Manager):控制分支(本地)事务,负责分支注册、状态汇报,并接受TC的指令,驱动本地事务的提交和回滚
1. 部署 Seata 服务器
服务端下载地址: https://github.com/seata/seata/releases
部署过程:略
2. seata客户端配置
在微服务的项目中,添加 Seata 的依赖。如果使用 Maven,可以在项目的 pom.xml 文件中添加以下依赖:
<dependency>
<groupId>io.seata</groupId>
<artifactId>·-all</artifactId>
<version>1.5.2</version> <!-- 请根据实际情况选择版本 -->
</dependency>配置文件
在微服务的配置文件中,配置 Seata 客户端。通常需要指定 Seata 服务器的地址等信息。以下是一个示例配置:
seata:
application-id: my-app
tx-service-group: my-tx-group
enabled: true
config:
type: nacos
nacos:
serverAddr: nacos-server:8848
groupId: SEATA_GROUP
namespace: ""
registry:
type: nacos
nacos:
serverAddr: nacos-server:8848
groupId: SEATA_GROUP
namespace: ""
service:
vgroup: "my-tx-group"
group: "my-tx-group"添加事务注解
使用 @GlobalTransactional 注解
在需要分布式事务的方法上,使用 @GlobalTransactional 注解标记。这个注解表示这个方法需要参与全局事务。
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@GlobalTransactional(rollbackFor = Exception.class)
public void businessMethod() {
// 业务逻辑
}
}参考