在 MySQL 中,错误代码 1205 表示“锁等待超时”(ER_LOCK_WAIT_TIMEOUT),通常发生在一个事务等待获取锁时,但超出了 innodb_lock_wait_timeout
参数设置的时间限制。这种情况常常导致数据库操作失败,影响应用性能。
1. 锁等待超时的常见原因
1.1 长事务
如果有一个事务在持有锁的情况下运行时间过长,其他事务就可能在等待该锁释放,最终导致超时。
1.2 死锁
多个事务相互等待对方持有的锁,形成死锁。这种情况下,MySQL 会自动检测并中止其中一个事务,但也可能会导致锁等待超时。
1.3 错误的锁策略
使用了不合适的锁策略,比如在需要锁定的表上执行了不必要的全表扫描,导致其他事务无法获得锁。
2. 锁等待超时的处理方法
2.1 调整超时设置
如果适用,可以增加 innodb_lock_wait_timeout
的值:
SET GLOBAL innodb_lock_wait_timeout = 120; -- 设置为 120 秒
2.2 优化事务
- 减少事务的持续时间:确保事务尽快完成,尽量减少锁的持有时间。
- 分拆大事务:将大事务分解为小事务,降低锁竞争的可能性。
2.3 检查死锁
使用 SHOW ENGINE INNODB STATUS
命令查看当前的死锁信息。这可以帮助您识别是哪两个或多个事务互相等待。
SHOW ENGINE INNODB STATUS;
根据输出的死锁信息,可以找到问题根源,并进行相应的代码或查询优化。
2.4 使用合适的索引
- 确保查询使用了合适的索引,以减少锁定的行数,降低锁竞争。
2.5 避免不必要的锁定
- 在执行 SELECT 查询时,尽量避免使用
SELECT ... FOR UPDATE
或SELECT ... LOCK IN SHARE MODE
,除非确实需要锁定。
2.6 监控和调试
- 定期监控数据库的锁情况和长事务,可以帮助及时发现并解决问题。
- 使用性能监控工具(如 MySQL Enterprise Monitor 或其他 APM 工具)来跟踪锁的使用情况和事务的执行时间。
3. 示例
假设您有两个事务可能导致锁等待超时:
事务 A
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
-- 这里可能会长时间等待
事务 B
START TRANSACTION;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 1; -- 等待事务 A 完成
如果事务 A 的执行时间过长,事务 B 将会因为无法获得锁而导致超时。这时您可以考虑优化事务 A,确保其尽快完成。