irpas技术客

Springboot整合Seata实现分布式事务_我有八千部下_springboot 分布式事务

网络 1755

文章目录 前言名词解释TC 配置TM / RM 配置AT (Automatic Transaction) 模式TCC (Try Confirm Cancel) 模式 如何解决 TCC 空回滚 幂等 悬挂问题?参考链接

前言

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

Seata 配置非常灵活,支持多种注册中心、配置来源(配置中心)和持久化方式。本文选择 eureka 作注册中心,本地文件作配置,用 MySQL 作持久化。

名词解释 TC (Transaction Coordinator) - 事务协调者 维护全局和分支事务的状态,驱动全局事务提交或回滚。TM (Transaction Manager) - 事务管理器 / 事务参与者 定义全局事务的范围:开始全局事务、提交或回滚全局事务。RM (Resource Manager) - 资源管理器 / 事务参与者 管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。TM 和 RM 都可以看成我们的业务服务,而 TM 是分布式事务开始的地方,调用链如 TM — RM — RM ~。 TC 配置 在 TC GitHub Releases 下载编译好的包解压。修改 /conf/registry.conf 配置注册中心和配置来源 registry { type = "eureka" eureka { serviceUrl = "http://localhost:8761/eureka" application = "seata-server" weight = "1" } } config { type = "file" file { name = "file.conf" } } 因为使用配置类型为 file, 修改对应 /conf/file.conf,指定 db 作为存储,并配置好数据库地址 ## transaction log store, only used in seata-server store { ## store mode: file、db、redis mode = "db" ## database store property db { ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc. datasource = "druid" ## mysql/oracle/postgresql/h2/oceanbase etc. dbType = "mysql" driverClassName = "com.mysql.jdbc.Driver" ## if using mysql to store the data, recommend add rewriteBatchedStatements=true in jdbc connection param url = "jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true" user = "root" password = "root" } }

注册(file 、nacos 、eureka、redis、zk、consul、etcd3、sofa)、配置(nacos 、apollo、zk、consul、etcd3)、存储(file、db、redis)方式有很多种方式,解压包里 conf/ 下配置文件各种配置方式都列出来了,只需要指定使用的方式,再修改对应类型的配置就行了。

创建数据库执行 TC MySQL 脚本

执行 bin/ 下脚本 seata-server.sh/bat 启动 TC 服务。

TM / RM 配置 pom.xml 添加依赖 <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-seata</artifactId> <version>${spring-cloud-alibaba-seata.version}</version> </dependency> resources/ 增加 registry.conf 配置文件。同 TC 一样指明使用 eureka 作注册中心,本地 file.conf 作配置来源 registry { # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa type = "eureka" eureka { serviceUrl = "http://localhost:8761/eureka" application = "seata-server" weight = "1" } } config { # file、nacos 、apollo、zk、consul、etcd3、springCloudConfig type = "file" file { name = "file.conf" } } resources/ 增加 file.conf 配置文件,修改下面项为 TC 注册到 eureka 的服务名 service { #transaction service group mapping vgroupMapping.my_test_tx_group = "seata-server" } AT (Automatic Transaction) 模式 AT 是 2PC 方案的一种实现。TM 先执行本地事务,并在 undo_log 表记录回滚日志但不提交,向 TC 申请全局锁成功后一起提交。紧接着调用后面的 RM,RM 同样记录回滚日志直接提交,不需要申请全局锁。最后所有参与者事务都执行成功,则 TC 通知提交,参与者会删掉回滚日志;如果有参与者执行失败通知 TC 后,TC 会通知参与者回滚,参与者根据日志回滚数据。全局锁是独占锁,占用期间并行的请求会在申请锁那一步等待。跟 2PC 比,AT 先提交了本地事务,不会长时间占用资源。

使用时只需要在 TM 服务事务方法上加注解 @GlobalTransactional,调用链后面的 RM 无需处理。 @GlobalTransactional public void purchase(String userId, String commodityCode, int orderCount) { storageFeignClient.deduct(commodityCode, orderCount); orderFeignClient.create(userId, commodityCode, orderCount); if (!validData()) { throw new RuntimeException("账户或库存不足,执行回滚"); } } TCC (Try Confirm Cancel) 模式

Seata TCC 三部操作对应 prepare、commit、rollback。

TM / RM 业务类需要一个接口,接口加上注解 @LocalTCC;业务接口上加 @TwoPhaseBusinessAction 并指明三个阶段执行的方法。然后实现类实现接口方法的具体逻辑。 import io.seata.rm.tcc.api.BusinessActionContext; import io.seata.rm.tcc.api.BusinessActionContextParameter; import io.seata.rm.tcc.api.LocalTCC; import io.seata.rm.tcc.api.TwoPhaseBusinessAction; @LocalTCC public interface ITccService { /** * Prepare */ @TwoPhaseBusinessAction(name = "tccTest", commitMethod = "tccTestCommit", rollbackMethod = "tccTestRollback") String tccTest(@BusinessActionContextParameter(paramName = "param1") String param1, @BusinessActionContextParameter(paramName = "param2") boolean param2); /** * Commit */ boolean tccTestCommit(BusinessActionContext businessActionContext); /** * Rollback */ boolean tccTestRollback(BusinessActionContext businessActionContext); } TM 则需要另外在调用事务方法的地方加注解 @GlobalTransactional。需要注意的是这个不能加到 Service 里面 。 @GlobalTransactional @RequestMapping("/tcc/rollback") public String purchaseRollback() { iTccService.tccTest(ThreadLocalRandom.current().nextInt() + "", true); return "全局事务提交"; } 如何解决 TCC 空回滚 幂等 悬挂问题?

增加事务控制表来解决,表主要包含全局事务id(transaction_id)、分支事务id(branch_id)、状态(state:1-已初始化、2-已提交、3-已回滚)。

空回滚

try 未执行的情况下执行了 cancel,比如开启全局事务后执行 try 超时了,但事务已经开启,需要推进到终态,因此 TC 通知执行 cancel,从而形成空回滚。

解决方案:执行 try 时在事务控制表插入一条记录,标记为1-已初始化。cancel 时检查记录存在,正常回滚;如果不存在,执行空回滚。

悬挂

cancel 优先 try 执行,同样是 try 超时,然后执行了空回滚后 try 开始执行。这种情况下应该让 try 不执行。

解决方案 :cancel、commit 的时候判断如果事务控制表没记录则插入对应状态的记录,try 执行前如果发现有记录则不执行。

幂等

TC 在通知参与者提交/回滚的时候,如果没收到反馈会重复通知。

解决方式:参与者处理完后修改事务控制表中的状态,处理前判断状态如果处理过,则不做任何处理。

参考链接

Seata 官网

Seata 中文文档

GitHub - TC 服务 Releases

GitHub - 官方使用例子程序

GitHub - Spring Cloud 快速集成 Seata

GitHub - 本文代码地址


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #springboot #分布式事务