跳到主要内容

项目中的分布式事务问题

由于项目使用了微服务架构,又进行了分库分表,也有不少同学提问项目中是如何解决分布式事务的,其实项目中已经通过业务来解决了。这里我总结一下。

一、为什么不用 Seata

官网中的示例

让我们从一个微服务示例开始。

用例

用户购买商品的业务逻辑。整个业务逻辑由 3 个微服务提供支持:

  • 仓储服务:对给定的商品扣除仓储数量。
  • 订单服务:根据采购需求创建订单。
  • 帐户服务:从用户帐户中扣除余额。

架构图

表关系

问题背景

  • 多服务参与同一笔业务(如“仓储”“账户”“主业务”)使用 Seata 的 AT 模式进行分布式事务。
  • 关注点:当一个全局事务正在修改“同一数据行”时,其他请求能否同时修改该行?是否必须等到当前全局事务的所有分支都结束后才能继续?

核心结论

  • 在“修改同一行”的前提下,后续对该行的写会被阻塞或重试,直到当前全局事务整体结束(全局提交或回滚)后才释放锁。
  • 锁是“行级全局锁”,按“表+主键”粒度生效,只影响冲突的那一行;其他不冲突的行、非强一致读不会被整体阻塞。

AT 模式如何工作

表关系
  • 两阶段事务:
    • 一阶段(本地执行/提交):每个分支在自己的本地事务中完成写入,同时记录 undo_log 并为所改行加“全局锁”( LockKey = 表名 + 主键 )。
    • 二阶段(全局提交/回滚):全局提交时释放锁;全局回滚时用 undo_log 恢复数据并释放锁。
  • 锁释放时机:发生在“全局事务结束”(提交或回滚),不是单个分支本地提交的时刻。

行为示例

场景:全局事务 xid1 包含分支 a1/b1/c1,三者都要修改同一行(例如库存表主键 S1 )。

  • 当 a1 已提交本地事务、b1 仍在执行、c1 已提交本地事务时,后续请求 a2 若要写同一行 S1 :
    • 会检测到该行的全局锁仍被 xid1 持有;
    • a2 的写要么等待、要么重试、要么失败(取决于客户端重试配置);
    • 只有当 xid1 整体“全局提交/回滚”后,锁释放,a2 才能获取锁并写入。

对比不冲突情况

  • a2 写不同主键(例如 S2 )→ 可并发执行,不受 S1 的锁影响。
  • 普通查询(非强一致读)→ 不受全局锁影响。

会阻塞与不会阻塞

  • 会阻塞:
    • 对同一 LockKey (同一表同一主键)的写操作。
    • 强一致读( SELECT ... FOR UPDATE 或使用 @GlobalLock )命中同一锁时。
  • 不会阻塞:
    • 写不同主键的行、写不同表的记录。
    • 普通读操作(非强一致),不会参与全局锁。

付费内容提示

该文档的全部内容仅对「JavaUp项目实战&技术讲解」知识星球用户开放

加入星球后,你可以获得:

  • 超级八股文:100万+字的全栈技术知识库,涵盖技术核心、数据库、中间件、分布式等深度剖析的讲解
  • 讲解文档:黑马点评Plus、大麦、大麦pro、大麦AI、流量切换、数据中台的从0到1的550+详细文档
  • 讲解视频:黑马点评Plus、大麦、大麦pro、大麦AI、流量切换、数据中台的核心业务详细讲解
  • 1 对 1 解答:可以对我进行1对1的问题提问,而不仅仅只限于项目
  • 针对性服务:有没理解的地方,文档或者视频还没有讲到可以提出,本人会补充
  • 面试与简历指导:提供面试回答技巧,项目怎样写才能在简历中具有独特的亮点
  • 中间件环境:对于项目中需要使用的中间件,可直接替换成我提供的云环境
  • 面试后复盘:小伙伴去面试后,如果哪里被面试官问住了,可以再找我解答
  • 远程的解决:如果在启动项目遇到问题,本人可以帮你远程解决
进入星球后,即可享受上述所有服务,保证不会再有其他隐藏费用。
知识星球二维码

1. 打开微信 -> 扫描左侧二维码 -> 加入「JavaUp项目实战&技术讲解」知识星球

2. 查看星球使用指导,获取完整项目讲解资料索引

👉 点击解锁全部付费内容
🎁优惠