2026年的Java面试,分布式事务几乎是必考项。面试官会从“你们项目怎么处理分布式事务的”切入,然后一路追问:2PC的原理是什么?有什么缺陷?TCC和2PC有什么区别?为什么你们不用TCC?最终一致性怎么保证?这一套“连环炮”打下来,能答透的人不超过30%。
分布式事务的核心问题其实很简单:一个业务操作跨越多个数据库或服务节点,如何保证原子性——要么全成功,要么全回滚。下面我把面试中最常被问到的三个方案拆开讲清楚。
第一炮:2PC(两阶段提交)——强一致的“老大哥”,但互联网项目很少用
2PC是分布式事务最经典的解决方案,核心思路是通过一个中心化协调者统一管理所有参与者的事务提交或回滚。整个过程分两个阶段:
准备阶段:协调者问所有参与者“能不能提交?”参与者执行预操作但不提交,锁定资源,返回YES或NO
提交阶段:全票通过就发Commit,有一个NO就全体回滚
优点很直接:强一致性,严格遵循ACID,数据库原生支持(MySQL XA协议),业务代码零侵入。
但缺陷同样致命:
同步阻塞:准备阶段所有参与者都锁着资源。有开发者反馈高峰期锁持有时间达500ms,业务操作本身才10ms,剩下全是等锁。
单点故障:协调者挂了,所有参与者卡在准备阶段无法释放资源。
脑裂风险:网络分区时,协调者可能给部分节点发提交、部分发回滚,数据就乱了。
面试官追问:“既然2PC问题这么多,你们项目用吗?”——实话实说:互联网高并发场景基本不用。2PC只适合低并发、短事务、对强一致性要求极高的场景,比如银行核心系统的内部账务调整。
第二炮:TCC(Try-Confirm-Cancel)——高性能的补偿方案,但开发成本极高
TCC是一种业务层侵入式的柔性分布式事务方案,将事务拆分为三个阶段:
Try:预留资源。比如转账场景,先把A账户100块冻结,不是直接扣掉
Confirm:确认提交。所有Try成功后,执行实际操作——把冻结的100块从A转到B
Cancel:取消回滚。任一Try失败,释放预留资源——把冻结的100块解冻
优势:相比2PC,TCC在Try阶段就完成了资源预留,无长时锁阻塞,性能优越。适合高并发、对一致性要求高的核心业务,如电商下单、秒杀。
但坑也很多:
空回滚:Cancel执行了,但Try根本没执行过。比如Try请求超时了,调用方以为失败就调Cancel,但Try其实成功了——钱已经冻结了。Cancel执行的时候,把没冻结的钱给“解冻”了,账对不上。
幂等问题:网络重试可能导致Confirm或Cancel被重复调用,必须用事务ID做幂等控制。
开发成本极高:每个业务接口都要实现Try/Confirm/Cancel三个方法,代码量翻三倍。
面试官常问:“TCC和2PC的本质区别是什么?”——2PC在数据库层面,TCC在应用层面。2PC锁的是数据库资源,TCC锁的是业务资源(比如冻结库存),粒度更细、性能更好,但业务代码侵入性极强。
第三炮:最终一致性——互联网项目的“最优解”
面试官最后通常会问:“那你们项目最终选了什么?”——大部分互联网项目,最终一致性方案才是答案。
最终一致性基于BASE理论(基本可用、软状态、最终一致性),允许短暂的数据不一致,但最终所有节点会达成一致。下单后库存扣减和订单创建中间差几毫秒,用户根本感知不到。
主要有两种实现方式:
本地消息表 + 消息队列:事务发起方在一个本地事务里同时写业务数据和消息表,然后通过定时任务轮询投递消息,下游消费后更新状态。优点是实现简单、不依赖特定中间件;缺点是定时轮询有延迟、消息表耦合业务。
事务消息(如RocketMQ):先发“半消息”(对下游不可见),执行本地事务,成功则提交半消息让下游可见,失败则回滚。RocketMQ还有回查机制,本地事务提交成功但确认消息丢了,会主动反查上游补偿。优点是吞吐高、解耦好;缺点是强依赖特定消息中间件。
面试官终极追问:怎么选?
面试官最后一定会问:“那这三种方案,你们怎么选?”——记住一句话:分布式事务没有银弹,能最终一致就别强一致。
决策逻辑很清晰:
强一致性优先 + 低并发→ 2PC(金融核心转账、清算)
强一致性优先 + 高并发→ TCC(支付、账户扣减,但要接受高开发成本)
可接受最终一致性 + 高吞吐→ 本地消息表或事务消息(电商下单、积分同步)
长事务(多步骤、耗时久)→ Saga模式(物流、供应链)
最后再补一句加分的话:“如果不想写太多补偿代码,可以考虑Seata的AT模式,无侵入自动回滚,但要接受全局锁带来的性能损耗,适合低并发场景”。
分布式事务没有完美方案,从业务容忍度出发做选型,才是落地的关键。这一套答下来,面试官基本就给你打上“真懂”的标签了。