锁冲突表现为SQL长时间不返回等,应通过performance_schema.data_lock_waits、INNODB_TRX、PROCESSLIST等定位锁等待链、活跃事务及阻塞源,并结合隔离级别、索引使用、事务控制习惯和慢日志综合分析。

查看当前锁等待和阻塞关系
锁冲突通常表现为某条 SQL 长时间不返回、应用超时或线程卡在 Waiting for table metadata lock / Waiting for global read lock / Updating 等状态。先通过以下语句定位正在发生锁等待的会话:
-
检查锁等待链:SELECT * FROM performance_schema.data_lock_waits;(MySQL 8.0+,需开启
performance_schema并配置相关 consumer) - 查看事务锁信息:SELECT * FROM information_schema.INNODB_TRX; 查看活跃事务及其运行时间、SQL、事务状态
- 查被阻塞的线程:SELECT * FROM information_schema.PROCESSLIST WHERE STATE LIKE 'Waiting%';
- 关联阻塞源:结合 INNODB_LOCKS(5.7)或 performance_schema.data_locks(8.0)与 INNODB_TRX 关联,找出持有锁但未提交的事务
确认锁类型和加锁范围
不是所有 SELECT 都无锁,也不是所有 UPDATE 都只锁一行。锁行为取决于隔离级别、索引使用、WHERE 条件是否走索引等:
-
普通 SELECT(非 FOR UPDATE/LOCK IN SHARE MODE):在
READ COMMITTED或REPEATABLE READ下不加行锁,但可能触发间隙锁(Gap Lock)或临键锁(Next-Key Lock),尤其在唯一索引失效或范围查询时 - UPDATE/DELETE 无有效索引:会升级为表级锁(全表扫描 + 行锁 → 实际效果接近表锁),极易引发大面积阻塞
- INSERT … ON DUPLICATE KEY UPDATE:会对冲突的唯一索引值加插入意向锁(Insert Intention Lock),若并发高且主键/唯一键分布集中,易与间隙锁冲突
- 显式加锁语句:SELECT ... FOR UPDATE 或 LOCK IN SHARE MODE 会按执行计划加锁,务必用 EXPLAIN 确认是否走了索引
分析事务生命周期和提交习惯
大部分锁冲突根源不在 SQL 本身,而在事务控制不当:
-
长事务不提交:一个事务持续数秒甚至分钟,期间持有的锁一直不释放。检查 INNODB_TRX 中
TRX_STARTED和TRX_MYSQL_THREAD_ID,结合 PROCESSLIST 定位对应连接的应用逻辑 -
应用层未正确关闭事务:比如异常分支漏写
ROLLBACK或COMMIT,或连接复用时事务状态残留 -
自动提交被关闭但未显式控制:SET autocommit = 0 后执行多条语句却忘记
COMMIT,后续语句都在同一事务中累积锁 -
大事务批量操作:如一次更新十万行,应拆分为小批量(如每次 1000 行),并确保每批后
COMMIT
结合慢日志与监控快速归因
单靠实时查询难覆盖历史冲突。建议组合使用以下手段构建分析闭环:
- 开启慢查询日志 + long_query_time=0(测试环境),或设置合理阈值(如 1s),捕获所有执行超时的语句,再反查其是否常出现在锁等待链中
- 定期采集锁相关指标:如 Innodb_row_lock_waits、Innodb_row_lock_time_avg(通过 SHOW STATUS),突增即预警
- 用 pt-deadlock-logger 监控死锁:自动记录死锁详情(涉及的事务、SQL、锁类型、索引),是分析高频冲突模式的关键依据
- 应用侧打点:在关键事务入口/出口记录 trace_id 和时间戳,当 DB 出现锁等待时,可反向关联到具体业务请求和代码路径










