Seata
Seata 是分布式事务解决方案,用于保证跨多个微服务的业务操作要么全部成功,要么全部失败,确保数据一致性。
微服务拆分后,一个业务需调用多个服务(例如:下单 → 扣库存 → 扣余额),Seata 防止部分服务成功、部分失败导致的数据错乱。
在spring中我们需要保持事物的一致性,所以使用注解@EnableTransactionManagement
和@Transactional
,这样当我们出现异常的时候就可以进行回滚,注意这只是本地服务。
在Seata里面有三个角色
-
TC(事务协调者):像个 “大管家”,盯着全局和分支事务的状态,决定是让事务提交成功还是回滚重来。
-
TM(事务管理器):是 “指挥官”,划定全局事务范围,负责开启、提交或者回滚全局事务 。
-
RM(资源管理器):当 “办事员”,管理分支事务要用的资源,还会和 TC 交流,汇报分支事务状态,执行提交或回滚 。
要想使用seata需要一个seata的客户端:下载地址:Seata-Server版本历史 | Apache Seata
安装之后在bin目录下使用:seata-server.bat启动,启动之后就可以访问端口http://127.0.0.1:7091/,我们的idea要想使用需要先引入依赖
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
我们的服务模块要想使用seata就需要进行文件的配置:
service {#transaction service group mappingvgroupMapping.default_tx_group = "default"#only support when registry.type=file, please don't set multiple addressesdefault.grouplist = "127.0.0.1:8091"#degrade, current not supportenableDegrade = false#disable seatadisableGlobalTransaction = false
}
配置文件只需要进行服务的指向即可,8091是TC协调者的地址,7091是seata的服务地址。
我们现在已经可以使用seata了,现在我们要使用seata可以使用@GlobalTransactional
我们只需要在最大的远程调用入口处使用即可。
二阶提交协议流程
当使用@GlobalTransactional
时,事务会先在 Seata 的 TC(事务协调者)处注册并开启全局事务,生成全局事务 ID。 全局事务开启后,各模块的分支业务执行时:RM 会先向 TC 注册分支事务并获取分支 ID;执行 SQL 前,通过 WHERE 条件查询数据的前镜像(执行前状态);执行 SQL 后,查询后镜像(执行后状态);将前后镜像写入 undo_log 日志,随后在同一本地事务中提交业务数据和 undo_log(确保原子性),同时申请全局锁防止并发修改;最后向 TC 汇报分支事务状态(成功 / 失败),第一阶段结束。 若所有分支事务成功,TC 触发第二阶段提交:RM 收到提交请求后,异步删除 undo_log;若有分支失败,TC 触发第二阶段回滚:RM 开启本地事务,通过全局 ID 和分支 ID 找到 undo_log,对比当前数据与后镜像(检测是否有脏写,有则需人工处理),无脏写则根据前镜像生成回滚 SQL 恢复数据,最后删除 undo_log。。
需注意:
-
Seata 分支事务无需强制标注 @Transactional,AT 模式下 RM 会自动管理本地事务;若业务需要本地事务增强,可添加,但不是必须。
-
全局锁时机:全局锁的申请是在执行 SQL 修改数据时(而非 “本地保存之前”),用于防止并发事务脏写。
当我们开启调试之后,进行断点测试,就可以在seata的控制器看到全局锁,锁的表。
我们通过undo_log日志可以很清楚的看到前镜像和后镜像
{"@class": "org.apache.seata.rm.datasource.undo.BranchUndoLog","xid": "192.168.74.1:8091:9688624833384463","branchId": 9688624833384465,"sqlUndoLogs": ["java.util.ArrayList",[{"@class": "org.apache.seata.rm.datasource.undo.SQLUndoLog","sqlType": "UPDATE","tableName": "account_tbl","beforeImage": {"@class": "org.apache.seata.rm.datasource.sql.struct.TableRecords","tableName": "account_tbl","rows": ["java.util.ArrayList",[{"@class": "org.apache.seata.rm.datasource.sql.struct.Row","fields": ["java.util.ArrayList",[{"@class": "org.apache.seata.rm.datasource.sql.struct.Field","name": "id","keyType": "PRIMARY_KEY","type": 4,"value": 1},{"@class": "org.apache.seata.rm.datasource.sql.struct.Field","name": "money","keyType": "NULL","type": 4,"value": 9946}]]}]]},"afterImage": {"@class": "org.apache.seata.rm.datasource.sql.struct.TableRecords","tableName": "account_tbl","rows": ["java.util.ArrayList",[{"@class": "org.apache.seata.rm.datasource.sql.struct.Row","fields": ["java.util.ArrayList",[{"@class": "org.apache.seata.rm.datasource.sql.struct.Field","name": "id","keyType": "PRIMARY_KEY","type": 4,"value": 1},{"@class": "org.apache.seata.rm.datasource.sql.struct.Field","name": "money","keyType": "NULL","type": 4,"value": 9928}]]}]]}}]]
}
Seata的四种模式
-
AT模式 (Auto Transaction):
-
总结: 自动生成反向SQL补偿,业务无感知。
-
例子: 电商下单(自动回滚扣减的库存和优惠券)。
-
-
TCC模式 (Try-Confirm-Cancel):
-
总结: 需手动编写 Try(预留)、Confirm(提交)、Cancel(取消) 逻辑。
-
例子: 转账业务(Try冻结A款、预留B款;Confirm实际划转;Cancel解冻/释放)。
-
-
Saga模式:
-
总结: 长事务,服务编排,每个服务提交即生效,失败则逆向补偿。
-
例子: 旅行预订(依次订机票、酒店,任一失败则取消之前成功的预订)。
-
-
XA模式:
-
总结: 基于数据库XA协议,强一致,全程锁资源。
-
例子: 银行核心系统跨行转账(严格保证A行扣款和B行入账同时成功或失败)。
-