真正生效需三步:永久配置写入my.cnf并重启;关键业务在连接池初始化时执行SET SESSION;必须开启innodb_rollback_on_timeout=ON,否则超时后事务状态不一致。

别调全局值就以为万事大吉——它只对新连接生效,旧连接照旧用老值,而生产环境的连接池基本不换连接。
怎么设才真正生效,而不是“改了等于没改”
你执行 SET GLOBAL innodb_lock_wait_timeout = 15 后,SHOW VARIABLES LIKE 'innodb_lock_wait_timeout' 看起来变了,但老连接仍用原来的值。这是因为 MySQL 不会强制重连,而 HikariCP、Druid 这类连接池默认长连接复用,可能几小时都不重建。
- 永久兜底:写进
/etc/my.cnf的[mysqld]段,加innodb_lock_wait_timeout = 15,再重启或mysqladmin reload(部分版本支持) - 关键路径收紧:在应用数据源初始化 SQL 中加
SET SESSION innodb_lock_wait_timeout = 5,确保每次新获取的连接都按需收紧 - 绝对别在业务 SQL 里插
SET SESSION:ORM(如 MyBatis)可能复用连接,你写的那句根本没机会执行;也难审计、易遗漏
设成多少才算合理,不是拍脑袋定的
默认 50 秒在高并发 OLTP 场景下是故障放大器:一个事务卡住一行,几十个后续请求排队等锁,全拖满 50 秒才失败,前端早超时了,后端线程池却还在等。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 金融类强一致操作(如支付扣款):
innodb_lock_wait_timeout = 5——错误秒级暴露,留给应用幂等重试的时间窗更宽 - 普通 Web 业务(如订单创建、评论提交):
innodb_lock_wait_timeout = 15——多数正常 DML 应在毫秒级完成,15 秒足够覆盖网络抖动,又不至于让单点卡顿拖垮整条链路 - 离线任务(如报表导出、日终跑批):
SET SESSION innodb_lock_wait_timeout = 300临时提升,但必须配合UPDATE ... LIMIT 1000+ 显式循环提交,否则单事务锁行过多,超时值再大也没用 - 绝不能设为 0 或 >300:0 是无限等待,极易引发连接堆积;>300 让问题延迟暴露,掩盖真实瓶颈
为什么调了还是报 Lock wait timeout exceeded
这个错误码是 ERROR 1205(注意:不是死锁错误 ERROR 1213),它只说明“等锁太久”,不说明“为什么等”。90% 的人一上来就调参,却漏掉三件事:
- 查谁在持锁:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW() - trx_started) > 60,找 TRX_STATE = 'RUNNING' 且持续超 60 秒的事务,定位对应应用代码 - 看 SQL 是否走索引:用
EXPLAIN检查UPDATE/DELETE的type是否为ALL或index,缺失索引会导致全表扫描+间隙锁升级,锁范围远超单行 - 检查事务里有没有非 DB 操作:HTTP 调用、文件读写、
SLEEP()—— MySQL 不知道你在等外部服务,它只认BEGIN到COMMIT的时长
最容易被忽略的配套动作
innodb_rollback_on_timeout = ON 必须开启。否则超时后事务状态不一致:锁释放了,但事务没回滚,后续语句可能基于脏数据继续执行,导致数据错乱。
另外,innodb_lock_wait_timeout 和 wait_timeout 得协同设:如果 wait_timeout = 28800(8 小时),而连接池没配 maxLifetime,那个“挂起的事务”可能空闲挂着几小时不提交,锁一直不放——这时调 innodb_lock_wait_timeout 根本没意义。

















