查看当前锁等待和阻塞关系
锁冲突通常表现为某条 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 出现锁等待时,可反向关联到具体业务请求和代码路径