发布时间:2026/8/24 15:51:38
SpringCloudAlibaba Seata分布式事务 AT模式 还有一篇文章是SpringCloudAlibaba Seata分布式事务那篇是14年总结的等找到工作抽时间整合到这块儿这篇文章的内容都DeepSeek提供的不得不说它的总结非常清楚明白所以这次面试的话可以利用DeepSeek重新整理一篇概念核心角色TC (Transaction Coordinator) - 事务协调器独立部署的调度中心负责维护全局事务和分支事务的状态驱动提交或回滚。TM (Transaction Manager) - 事务管理器嵌入在应用中的“事务发起者”用GlobalTransactional定义全局事务边界。RM (Resource Manager) - 资源管理器管理每个分支事务即本地数据库操作负责向TC注册、上报状态并执行提交/回滚指令。其中TC为单独部署的Server服务端TM和RM为嵌入到应用中的 Client 客户端TC就是事务管理器RM就是每个数据库连接或者说本地事务TM就是事务的入口或者说事务的发起方当然它本身也是一个RM执行流程TM请求TC开启一个全局事务TC会生成一个XID作为该全局事务的编号XID会在微服务的调用链路中传播保证将多个微服务的子事务关联在一起RM请求TC将本地事务注册为全局事务的分支事务通过全局事务的XID进行关联TM请求TC告诉XID对应的全局事务是进行提交还是回滚TC驱动RM将XID对应的自己的本地事务进行提交还是回滚每个微服务都需要有一个undo_log表用于自动补偿例如一个事务已经提交了但这时发生了异常此时该事务已经无法回滚了。在提交事务之前会查询一下要执行事务涉及到的表数据并记录在undo_log表中如果发生了上面的情况则将数据自动改回去而不需要我们敲代码来执行这个操作。二阶段提交精髓在于“一阶段提交二阶段补偿”第一阶段PrepareTM向TC申请开启全局事务生成全局唯一的XID并传播到各个微服务。RM执行业务SQL同时Seata的数据源代理会拦截SQL记录数据修改前后的镜像before-image和after-image作为回滚日志undo_log保存在当前数据库中。在本地事务提交前RM会向TC申请一个全局锁针对修改的数据行。拿到全局锁后本地事务提交业务数据更新生效本地锁被释放。这个“一阶段就提交并释放本地锁”是AT模式高性能的关键。第二阶段Commit / Rollback全局提交如果所有分支都成功TC通知各RM异步删除undo_log并释放全局锁非常快。全局回滚如果任一分支失败TC通知所有RM进行回滚。RM根据XID找到对应的undo_log用before-image的旧数据生成反向SQL如补偿更新将数据恢复然后删除日志并释放全局锁。关键机制 Undo Log与全局锁Undo Log回滚日志这是AT模式实现自动回滚的核心。它在每个参与事务的数据库中必须创建一张undo_log表记录数据更新前后的快照。通过解析这些快照Seata能在需要时自动生成补偿SQL对业务代码零侵入。隔离性实现Seata AT模式的隔离性基于“全局锁”实现写隔离核心是“先抢全局锁再提交本地事务”。不同全局事务要修改同一行数据时必须先获得该行的全局锁。这有效防止了脏写但引入全局锁竞争也是其性能瓶颈之一。读隔离默认是读未提交因为一阶段已提交。如果需要“读已提交”的强隔离需在查询SQL中使用SELECT … FOR UPDATE此时Seata会代理该语句去申请全局锁从而读到已提交的数据测试seata:enabled:trueapplication-id:awu-springboot-code-1# 事务分组名称你可以随便起但必须和下面 mapping 的 key 对应tx-service-group:default_tx_groupregistry:type:nacosnacos:server-addr:192.168.239.3:8848username:nacospassword:nacos# 关键桥梁告诉客户端你的 default_tx_group 去找 Nacos 里名为 default 的集群Seata 2.0 服务端默认就是注册到 defaultservice:vgroup-mapping:default_tx_group:defaultpackagecom.awu.springboot.code1.controller;importcom.awu.springboot.code1.feign.OrderFeignClient;importio.seata.spring.annotation.GlobalTransactional;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;RestControllerRequestMapping(/distributed-tx-test)publicclassDistributedTxTestController{AutowiredprivateOrderFeignClientorderFeignClient;// ⚠️ 全局事务注解加在发起入口GetMapping(/user-place-order)GlobalTransactionalpublicStringuserPlaceOrder(){System.out.println( 开始Code1用户下单入口 );// 模拟 用户下单主表入库System.out.println(【成功】Code1 用户下单记录写入数据库成功);System.out.println(--- Code1 准备调用 Code2 生成订单 ---);returnorderFeignClient.createOrder();}}packagecom.awu.springboot.code2.controller;importcom.awu.springboot.code2.feign.StockFeignClient;importcom.awu.springboot.code2.mapper.User;importcom.awu.springboot.code2.mapper.UserMapper;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;RestControllerRequestMapping(/distributed-tx-test)publicclassDistributedTxTestController{AutowiredprivateStockFeignClientstockFeignClient;AutowiredUserMapperuserMapper;GetMapping(/create-order)publicStringcreateOrder(){System.out.println( 1. 进入 Code2订单服务 );// 模拟 生成订单写入数据库System.out.println(【成功】Code2 生成订单成功(假装写入了订单表));User张三newUser(1L,张三,55);userMapper.updateById(张三);System.out.println( 1. 进入 Code2订单服务 );System.out.println(当前 XID: io.seata.core.context.RootContext.getXID());System.out.println(--- Code2 准备调用 Code3 扣减库存 ---);returnstockFeignClient.decreaseStock();}}packagecom.awu.springboot.code3.controller;importcom.alibaba.fastjson.JSON;importcom.awu.springboot.code3.mapper.User;importcom.awu.springboot.code3.mapper.UserMapper;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;RestControllerRequestMapping(/distributed-tx-test)publicclassDistributedTxTestController{// Autowired// private StockService stockService; // 你的库存ServiceAutowiredUserMapperuserMapper;GetMapping(/decrease-stock)publicStringdecreaseStock(){System.out.println( 2. 进入 Code3扣减库存服务 );// 模拟 扣减数据库库存System.out.println(【成功】Code3 扣减库存成功(假装从数据库扣了 1 件));// 这里测试脏读会读取到code2服务的脏数据UseruseruserMapper.selectById(1L);System.out.println(JSON.toJSONString(user));// 这里模拟一个异常用于测试全局回滚// User lisi new User(2L, 李四, 22);// userMapper.updateById(lisi);// ⚠️ 重点制造全局回滚异常// System.out.println(--- Code3 检测到异常情况准备回滚 ---);// throw new RuntimeException(【模拟报错】Code3 库存扣减服务发生故障触发全局回滚);return扣减成功;}}问题同一个全局事务内的脏读问题code1远程调用code2code2修改了当前行数据code2远程调用code3code3读取了当前行数据他们在同一个全局事务内那么code3是读到了code2修改前的还是修改后的数据呢是修改后的数据因为同一个事务内修改后的数据是可见的Seata 的设计是同一个全局事务内的分支事务对该事务自己持有的锁是“可重入”的。Code2和Code3属于同一个全局事务Code2加的锁Code3可以直接通过不会阻塞等待。如果Code2和Code3在同一个全局事务中Code3读到Code2的未提交数据是符合 Seata 设计预期的。这并不算真正的“脏读”而是同一事务内的数据可见性。解决方案先调用code3后调用code2不同全局事务的脏读处理for update GlobalLock Transactional这可以解决不同事务之间的脏读问题它会去获取全局锁我们可以设置重试时间让它直到获取锁成功为止才读到数据这样就避免了脏读的问题。seata:client:rm:lock:# 全局锁重试间隔毫秒默认 10msretry-interval:10# 全局锁重试次数默认 30 次retry-times:300000# 如果设为 true则重试次数无限retry-policy-branch-rollback-on-conflict:falseenabled:trueapplication-id:awu-springboot-code-3# 事务分组名称你可以随便起但必须和下面 mapping 的 key 对应tx-service-group:default_tx_groupregistry:type:nacosnacos:server-addr:192.168.239.3:8848username:nacospassword:nacos# 关键桥梁告诉客户端你的 default_tx_group 去找 Nacos 里名为 default 的集群Seata 2.0 服务端默认就是注册到 defaultservice:vgroup-mapping:default_tx_group:defaultGetMapping(“/dirty-read”)public String dirtyRead() {User user userService.selectByIdForUpdateDirtyRead(1L);log.info(“测试不同事务”);return JSON.toJSONString(user);}OverrideGlobalLockTransactionalpublic User selectByIdForUpdateDirtyRead(Long id) {// 测试用for update避免脏数据这里seata会去拿全局锁User user userMapper.selectByIdForUpdate(1L);System.out.println(JSON.toJSONString(user));return user;}Select(“SELECT * FROM user WHERE id #{id} FOR UPDATE”)User selectByIdForUpdate(Long id);AT 模式脏写问题 ⭐非常常问二阶段提交 / 回滚消息丢失怎么办幂等怎么保证全局锁超时时间在绝望的时候朱重八不止一次地祈求上天从道教地太上老君到佛教的如来佛祖只要他能知道的名字都祈求到了祈祷的唯一内容只是希望与父母在一起生活下去有口饭吃。明朝那些事儿当年明月

相关新闻

2026/8/24 15:51:38

长春燃气/电热水器维修上门服务-欧米到家持证师傅正规检修|深度排查不出热水漏水忽冷忽热等故障

冬季洗澡水温异常、热水器漏水、不出热水、运行异响、水温忽冷忽热,是长春家庭热水器最常见的故障。很多长春用户网上找维修师傅,容易遭遇小病大修、隐形收费、劣质配件等问题。市面上多数维修内容内容零散、实用性差,无法适配长春老小区水压…

2026/8/24 15:51:38

Chrome 偷吃 4GB 硬盘?把本地 AI 模型删干净并禁止它再下载

先说结论 最近有些机器上的 Google Chrome 会在用户没有明确感知的情况下,下载一份约 4GB 的本地生成式 AI 模型数据。它通常不是病毒,也不是缓存异常,而是 Chrome 为本地 AI 功能准备的模型文件。只删除目录只能临时释放空间,真正…

2026/8/24 23:19:10

SpringBoot3+Vue3全栈求职系统开发实战

1. 项目概述:从零构建在线求职系统全栈方案这套SpringBoot3Vue3在线求职系统教程,是我为计算机专业毕业生和全栈开发初学者设计的实战型教学方案。不同于市面上简单的CRUD示例,我们以真实的招聘平台业务逻辑为核心,完整覆盖前后端…

2026/8/24 23:19:10

Roo Code 实战指南:把一支 AI 开发团队装进 VS Code

Roo Code 实战指南:把一支 AI 开发团队装进 VS Code 【免费下载链接】Roo-Code Roo Code gives you a whole dev team of AI agents in your code editor. 项目地址: https://gitcode.com/GitHub_Trending/ro/Roo-Code Roo Code 是一款 VS Code 插件&#xf…

2026/8/24 23:19:10

wewe-rss 订阅聚合 API 实用指南:获取、过滤与转换公众号订阅

wewe-rss 订阅聚合 API 实用指南:获取、过滤与转换公众号订阅 【免费下载链接】wewe-rss 🤗更优雅的微信公众号订阅方式,支持私有化部署、微信公众号RSS生成(基于微信读书) 项目地址: https://gitcode.com/GitHub_Tr…

2026/8/24 23:14:10

信号链设计全解析:从传感器到ADC的硬件工程实践

1. 信号链:从物理世界到数字世界的“翻译官”如果你曾经好奇过,为什么手机能听到千里之外的声音,智能手表能测出你的心率,或者自动驾驶汽车能“看见”前方的障碍物,那么你其实已经在接触“信号链”这个概念了。信号链&…

2026/8/24 0:07:22

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/24 1:12:32

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/24 8:17:29

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/24 1:09:25

3条命令跑通LocalAI:无GPU本地AI引擎部署

3条命令跑通LocalAI:无GPU本地AI引擎部署 【免费下载链接】LocalAI LocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required. 项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAI…

2026/8/24 1:09:25

AI推理性能测试怎么做:MLPerf Inference完整上手指南

AI推理性能测试怎么做:MLPerf Inference完整上手指南 【免费下载链接】inference Reference implementations of MLPerf inference benchmarks 项目地址: https://gitcode.com/gh_mirrors/inf/inference 同一个模型换一张卡,速度快多少你知道吗&a…

2026/8/24 13:42:17

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/24 18:13:48

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/23 4:22:01

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…