一文搞懂分布式事务:从理论到实践方案
在分布式系统中,一个核心操作常拆分为多个小操作,分散在不同服务器、不同应用中 ------ 比如电商下单,要同时修改订单库、库存库、支付库的数据。这就需要分布式事务来保障:这些小操作要么全部成功,要么全部失败,本质是保证不同数据库的数据一致性。
本文将从理论基础(CAP、BASE)到规范(XA、JTA),再到实践方案(2PC、3PC、TCC、Seata),逐步拆解分布式事务的核心逻辑。
一、理论基础:CAP 定理与 BASE 理论
分布式事务的设计,首先要围绕 "一致性" 和 "可用性" 的平衡展开,这就离不开 CAP 和 BASE 两大理论。
1. CAP 定理:三选二的必然选择
CAP 分别代表一致性(Consistency) 、可用性(Availability) 、分区容错性(Partition Tolerance) :
- 一致性:数据分布在多个节点,某个节点更新后,其他节点能立即读到最新数据(强一致性);若读不到,则为不一致。
- 可用性:非故障节点需在合理时间内返回正确响应,不能无响应或报错。
- 分区容错性:网络分区(如部分节点断连)时,系统仍能正常工作。
核心结论:分布式系统必须保证 P(分区容错性是分布式的基础),因此只能在 "CP" 和 "AP" 中选其一:
- 选 CP(强一致性) :如 ZooKeeper、MongoDB。网络分区时,为避免数据不一致,会牺牲可用性 ------ 比如节点 A 更新后无法同步到节点 B,系统会暂停服务,不让用户读到不一致数据。
- 选 AP(高可用性) :如 12306、电商平台。网络分区时,优先保证服务可用,允许短暂数据不一致 ------ 比如用户看到的库存是旧的,但实际下单时会再次校验,避免超卖。
2. BASE 理论:AP 的 "柔性妥协"
BASE 是对 AP 的扩展,追求基本可用(Basic Availability) 、软状态(Soft State) 、最终一致性(Eventual Consistency) ,是 CAP 中 "放弃强一致性、保可用性" 的落地指导:
- 基本可用:允许损失部分非核心服务,保证核心功能可用 ------ 比如电商大促时,关闭 "商品评价" 功能,优先保障 "下单付款"。
- 软状态:允许系统存在中间状态(如 "订单待支付"),不影响整体可用性。
- 最终一致性:短期内数据可能不一致,但经过一段时间(如同步延迟),所有节点数据会趋于一致。
BASE 与 ACID(数据库事务的原子性、一致性、隔离性、持久性)相反:ACID 追求强一致性,BASE 则用 "最终一致" 换可用性,解决分布式系统的网络延迟问题。
二、核心规范:XA 与 JTA
有了理论基础,分布式事务需要具体规范来定义角色和交互逻辑,最经典的是 XA 规范和 JTA API。
1. XA 规范:定义分布式事务角色与接口
XA 是 X/Open 组织制定的分布式事务模型,核心是明确 4 个角色和交互接口:
- Application(应用) :发起事务的服务实例(如订单服务)。
- TM(事务管理器) :协调全局事务的组件,负责通知各节点提交 / 回滚。
- RM(资源管理器) :数据库,负责执行本地事务(如订单库、库存库)。
- CRM(通信资源管理器) :可选,如消息中间件,用于跨服务通信。
全局事务:XA 定义的核心概念 ------ 横跨多个 RM 的事务,需保证 "一个 RM 失败,所有 RM 都回滚"。XA 的关键是:定义 TM 与 RM 的交互接口,让 TM 能统一控制所有 RM 的提交 / 回滚,具体实现由数据库厂商提供(如 MySQL 支持 XA)。
2. JTA:Java 中的分布式事务 API
JTA(Java Transaction API)是 Java 领域对 XA 规范的实现,属于 J2EE 体系:
- 单库事务用 JDBC 事务(如Connection.commit());
- 跨库事务用 JTA API,通过 TM 协调多个 RM,需结合 JNDI(Java 命名服务)使用。
现状:JTA 规范虽完善,但近年在分布式微服务场景中很少使用 ------ 过于依赖 J2EE 环境,灵活性不足。
三、经典方案:从 2PC 到 3PC
基于 XA 规范,最经典的分布式事务实现是 "两阶段提交(2PC)" 和 "三阶段提交(3PC)",核心是通过 "分阶段协调" 保证一致性。
1. 两阶段提交(2PC):简单但有缺陷
2PC 是 XA 的典型实现,分 "准备阶段" 和 "提交阶段":
- 阶段 1:准备(Prepare)
TM 向所有 RM 发送 "准备请求",RM 执行本地事务(如扣减库存),写入 Undo Log(回滚日志)和 Redo Log(重做日志),但不提交;执行成功后,RM 向 TM 返回 "就绪",否则返回 "失败"。
- 阶段 2:提交 / 回滚(Commit/Abort)
若所有 RM 都返回 "就绪",TM 发送 "提交请求",RM 提交事务并释放锁;若有 RM 返回 "失败",TM 发送 "回滚请求",RM 通过 Undo Log 回滚。
缺陷:
- 同步阻塞:RM 等待 TM 指令时,会锁定资源,无法处理其他请求,不支持高并发;
- 单点故障:TM 宕机后,RM 会一直卡在 "就绪" 状态,无法释放资源;
- 脑裂问题:阶段 2 中,部分 RM 收到 "提交" 指令,部分没收到,导致数据不一致;
- 状态丢失:TM 热备时,若某 RM 已提交但 TM 宕机,新 TM 无法获知该 RM 状态。
2. 三阶段提交(3PC):优化 2PC 的缺陷
3PC 在 2PC 基础上增加 "预准备阶段" 和 "超时机制",解决部分问题:
- 阶段 1:预准备(CanCommit)
TM 发送 "是否可提交" 请求,RM 仅检查自身状态(如网络、资源是否可用),不执行实际事务,返回 "就绪" 或 "失败"------ 此阶段无资源锁定。
- 阶段 2:准备(PreCommit)
若所有 RM "就绪",TM 发送 "预提交请求",RM 执行事务(写日志,不提交);若有 RM "失败",TM 发送 "中止请求",事务结束。
- 阶段 3:提交(DoCommit)
若所有 RM "预提交成功",TM 发送 "提交请求";若有 RM "失败" 或超时,TM 发送 "回滚请求"。
优化点:
- 超时机制:RM 若超时未收到 TM 指令,会自动提交(基于 CanCommit 阶段确认的 "自身可用"),避免资源长期锁定;
- 减少阻塞:CanCommit 阶段无资源锁定,降低同步阻塞影响。
缺陷:仍未解决脑裂问题 ------ 若阶段 3 中,部分 RM 没收到 "回滚" 指令,会自动提交,导致数据不一致。
四、实战方案:TCC、Seata 与更多
2PC/3PC 依赖数据库层,灵活性不足,实际业务中更常用 TCC、可靠消息、Seata 等方案。
1. TCC:应用层的 "两阶段提交"
TCC(Try-Confirm-Cancel)是在应用层实现分布式事务,核心是为每个业务操作定义 "准备、确认、补偿" 三个接口,不依赖数据库 XA 接口。

核心逻辑(三阶段):
- Try:业务检查 + 资源预留 ------ 如下单时,检查库存是否足够,锁定库存(不扣减)。
- Confirm:确认业务操作 ------ 如扣减已锁定的库存,此阶段需保证 "一定成功"(失败则重试)。
- Cancel:补偿回滚 ------ 如释放 Try 阶段锁定的库存,恢复资源。
执行流程:
- TM 发起所有 RM 的 Try 操作;
- 若所有 Try 成功,TM 发起所有 RM 的 Confirm 操作;
- 若任一 Try 失败,TM 发起所有 RM 的 Cancel 操作。
关键问题与解决:
- 幂等性:用 "事务状态表" 记录状态(INIT/CONFIRMED/ROLLBACKED),重复调用时先查状态,避免重复执行;
- 空回滚:Cancel 时查状态表,若 Try 未执行(无 INIT 记录),则不处理;
- 资源悬挂:Cancel 执行后,若 Try 请求延迟到达,通过状态表拦截(已存在 Cancel 记录则拒绝 Try)。
适用场景:
强隔离性、短耗时业务(如支付扣款、积分兑换),但对应用侵入性强 ------ 每个业务需写 Try/Confirm/Cancel 接口。
2. 其他常见方案
方案 | 核心逻辑 | 适用场景 |
---|---|---|
可靠消息最终一致 | 用消息中间件异步同步数据,失败则重试 | 耗时业务(如订单创建后发通知) |
最大努力通知 | 异步通知 + 有限次重试,不保证 100% 成功 | 非核心业务(如短信提醒) |
ByteTCC 框架 | 封装 TCC 逻辑,自动重试 Confirm,用数据库记录事务状态 | 简化 TCC 开发,需建专用日志表 |
3. Seata:开源分布式事务框架
Seata 是阿里开源的分布式事务解决方案,支持 AT、TCC、SAGA、XA 四种模式,开箱即用,是当前微服务场景的主流选择。

核心角色:
- TC(Transaction Coordinator) :Seata 服务端,协调全局事务;
- TM(Transaction Manager) :应用端,发起 / 结束全局事务;
- RM(Resource Manager) :数据库端,执行本地事务,向 TC 注册分支事务。
主流模式:AT 模式(基于 2PC 的优化)
AT 模式依赖支持 ACID 的关系型数据库,无需改业务代码,核心是 "自动生成回滚日志":
- 一阶段:RM 执行本地事务(如扣库存),同时写入 "回滚日志"(记录数据修改前的状态),一并提交;
- 二阶段提交:TM 通知 TC 提交,TC 异步清理回滚日志,快速结束;
- 二阶段回滚:TC 通知 RM,RM 通过回滚日志生成 "补偿操作"(如恢复库存),完成回滚。
优势:对业务无侵入,性能优于传统 2PC,适合微服务场景。
总结
分布式事务的核心是 "平衡一致性与可用性":
- 理论上,CAP 定调 "P 必选,CP/AP 二选一",BASE 用 "最终一致" 落地 AP;
- 规范上,XA 定义角色接口,JTA 是 Java 实现,但灵活性不足;
- 实践上,2PC/3PC 是基础方案,TCC 适合强一致场景,Seata(AT 模式)是微服务首选,可靠消息适合异步场景。
实际开发中,需根据业务优先级(如 "支付需强一致,通知可最终一致")选择方案,避免过度追求 "强一致" 导致可用性下降。