最后更新:2026-10-23 · 基于第 1 次作答
结论:全局锁是 TC 侧的行级逻辑锁,用于跨全局事务冲突检测;本地锁是数据库行锁,业务提交即释放。冲突时全局事务不阻塞本地事务,而是无限重试直到超时。 关键词:TC lock_table · 行级全局锁 · 冲突检测 · 无限重试 边界:全局锁不阻塞本地事务提交,只阻塞全局事务的推进。
核心考点定位:能否分清"全局锁"与"本地锁"锁的对象不同,并说清冲突时的真实表现是全局事务重试,而不是本地事务被阻塞。
机制链(≥3 环):
证据锚点:
TC lock_table:全局锁的存储位置,行级粒度,key 为 xid + table_name + pk。本地行锁(InnoDB Record Lock):数据库物理锁,业务事务提交即释放。undo_log:与业务数据同事务提交,是回滚补偿依据。lockRetryTimes:全局锁申请失败后的重试次数,默认 -1 表示无限重试。lockRetryInterval:重试间隔,默认 10ms。全局事务超时(defaultTimeout):默认 60s,超时后触发全局回滚。对比与权衡:
| 维度 | 全局锁 | 本地锁 |
|---|---|---|
| 持有者 | TC(协调器) | 数据库实例 |
| 粒度 | 行级(逻辑) | 行级(物理) |
| 持有时间 | 全局事务生命周期 | 本地事务生命周期 |
| 作用 | 跨全局事务冲突检测 | 保证本地事务隔离性 |
| 释放时机 | 全局事务提交/回滚 | 本地事务提交/回滚 |
常见误区:
适用边界:全局锁适合行级冲突稀疏的场景;热点行(如库存扣减、账户余额)会导致大量全局事务重试,应改用 TCC 或独立库存服务。
【结论】 面试官您好,全局锁是 Seata TC 侧维护的行级逻辑锁,用于跨全局事务的冲突检测;本地锁是数据库自己的行锁,本地事务提交就释放。两者锁的对象和持有时间完全不同。
【三点】 第一,一阶段执行时,业务 SQL 通过 Seata 的 JDBC 代理执行,Seata 会先在 TC 侧申请这一行的全局锁,同时数据库持有本地行锁。业务本地事务提交后,本地行锁立即释放,undo_log 和业务数据一起落库,但全局锁继续由 TC 持有,直到全局事务提交或回滚。第二,冲突是这样发生的:另一个全局事务要修改同一行时,TC 发现该行已被占用,申请失败。关键点在于——这个失败不会阻塞本地事务,本地事务照常提交;被阻塞的是这个全局事务本身的推进。Seata 默认按 10ms 间隔无限重试申请全局锁,直到全局事务超时(默认 60 秒)才触发全局回滚。第三,所以"本地锁冲突导致全局事务长时间等待"的准确表述是:本地事务之间如果存在锁冲突,会让某个全局事务的一阶段迟迟无法提交,全局锁就一直持有不释放,后续所有要改同一行的全局事务都会在 TC 侧重试等待,最终集体超时。
【边界】 当然,全局锁是行级的,冲突稀疏时开销很小;但热点行场景(库存扣减、账户余额)会让大量全局事务在 TC 侧重试堆积,超时回滚率飙升,这时应该改用 TCC 或把热点资源拆成独立服务,而不是继续用 AT。
题目:Seata AT 模式中,全局锁和本地锁分别锁什么?为什么会出现本地锁冲突导致全局事务长时间等待?
难度:medium
标签:arch/distributed/transaction, distributed/seata, distributed/lock
评分:⭐⭐☆☆☆(2/5)
练习次数:1
AT模式中是先执行本地事务,通过本地的数据库事务锁来保证本地事务的执行,只有本地事务执行完毕,才会去通知Seata进行全局锁解开,如果数据库自身执行的本地锁的数据任务不能正常执行,那么也就会导致SeataAT模式的全局锁一直持有无法释放;
评分:⭐⭐☆☆☆(2/5)
优点:
不足:
补充:
完整讲解见上方「完整讲解(权威版)」