锁等待发生在事务持有锁时另一事务请求不兼容锁,导致阻塞。通过performance_schema查看data_locks和data_lock_waits,结合innodb_trx识别等待事务,可缩短事务、优化索引、设置超时、终止阻塞事务及调整隔离级别来处理,预防需避免长事务与全表扫描,按序访问表并监控异常。

在MySQL中,锁等待是事务并发控制的重要机制。当多个事务同时访问同一数据资源时,MySQL通过加锁来保证数据的一致性和隔离性。但锁也可能导致“锁等待”甚至“死锁”,影响系统性能。理解并合理处理锁等待问题,对数据库优化至关重要。
锁等待是如何发生的
当一个事务持有了某行或某表的锁(如排他锁X锁),另一个事务尝试获取相同资源上的不兼容锁时,后者就会进入“锁等待”状态,直到前一个事务释放锁或者超时。
常见场景包括:
- 事务A执行UPDATE users SET name='Tom' WHERE id=1;但未提交,事务B再执行同样的UPDATE或SELECT ... FOR UPDATE就会被阻塞。
- 长事务长时间持有行锁,其他事务需等待。
- 索引缺失导致扫描范围扩大,锁住更多行,增加冲突概率。
如何查看锁等待信息
MySQL提供了多种方式查看当前的锁和等待情况,主要依赖information_schema中的表:
1. 查看锁等待状态:
SELECT * FROM information_schema.innodb_locks; -- 已废弃(MySQL 8.0前)在新版本中应使用 performance_schema:
2. 使用 performance_schema 查看锁信息:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES'
WHERE NAME LIKE 'wait/synch%';
SELECT FROM performance_schema.data_locks;
SELECT FROM performance_schema.data_lock_waits;
3. 查看正在运行的事务:
SELECT * FROM information_schema.innodb_trx ORDER BY trx_started;-- 关注 trx_state、trx_wait_started、trx_mysql_thread_id 字段
其中,如果trx_state为LOCK WAIT,说明该事务正在等待锁。
如何处理锁等待问题
发现锁等待后,可采取以下措施缓解或解决:
- 缩短事务长度:尽快提交或回滚事务,减少锁持有时间。
- 合理使用索引:避免全表扫描,减少不必要的行锁。
-
设置锁等待超时:
SET innodb_lock_wait_timeout = 50; -- 默认50秒,单位秒
超时后事务将自动回滚并报错Lock wait timeout exceeded。 -
分析并终止阻塞事务:
找出长时间运行的事务(通过information_schema.innodb_trx),必要时用KILL [thread_id]终止。 -
调整隔离级别:
如从REPEATABLE READ降到READ COMMITTED,可减少间隙锁的使用,降低锁冲突。
预防锁等待的建议
良好的设计能显著降低锁等待发生概率:
- 避免在事务中执行耗时操作(如网络调用、大量计算)。
- 按固定顺序访问多张表,减少死锁风险。
- 使用
SELECT ... FOR UPDATE或LOCK IN SHARE MODE时明确目的,避免过度加锁。 - 定期监控长时间运行的事务,建立告警机制。
基本上就这些。掌握锁等待的原理和排查方法,能帮助你快速定位数据库性能瓶颈,提升系统的稳定性和响应速度。










