查死锁必须执行show engine innodb status\g查看latest detected deadlock区块,并确保innodb_print_all_deadlocks=on;事务中禁用query()/execute(),统一用querybuilder方法;sql需走索引、避免函数运算;控制事务粒度与超时,不嵌套事务。

查死锁得先看 MySQL 的 innodb_status
ThinkPHP 本身不暴露死锁细节,真正抛出的 SQLSTATE[40001]: Serialization failure 或 Deadlock found when trying to get lock 只是结果。必须进数据库查根源:SHOW ENGINE INNODB STATUS\G,重点看 LATEST DETECTED DEADLOCK 区块——它会明确写出哪两个事务、在哪个表/行、持有什么锁、等待什么锁。
- 执行前确保 MySQL 开启了死锁日志:配置项
innodb_print_all_deadlocks = ON(写入 my.cnf 并重启),否则只保留最后一次死锁记录 - ThinkPHP 日志里搜不到完整死锁链,别指望
think.log里有WAITING FOR THIS LOCK TO BE GRANTED这类信息 - 如果用的是云数据库(如阿里云 RDS),控制台一般提供「死锁日志」独立页面,比手动查
INNODB STATUS更直观
事务里混用 query() 和 execute() 容易触发隐式提交
ThinkPHP 的 Db::transaction() 底层靠 PDO 的 beginTransaction()/commit() 控制,但一旦你在事务中调用了 Db::query()(比如执行 SELECT COUNT(*))或 Db::execute()(比如 INSERT INTO ... SELECT),某些 MySQL 隔离级别下会触发隐式提交,导致事务提前结束——后续语句实际不在事务内,锁没被统一释放,死锁概率陡增。
- 统一用
Db::table()->select()、Db::table()->insert()等 QueryBuilder 方法,它们会走 PDO 的预处理通道,不触发隐式提交 - 避免在事务中执行 DDL(如
CREATE TEMPORARY TABLE),MySQL 会强制提交当前事务 - 调试时可在事务开头加
Db::raw('SELECT CONNECTION_ID()'),再在每步后查information_schema.PROCESSLIST,确认是否仍是同一个 connection_id
锁粒度失控:没走索引 or 间隙锁误伤
死锁常源于 UPDATE/DELETE 语句没命中索引,导致全表扫描并锁住所有行;或 WHERE 条件落在索引间隙上,触发间隙锁(Gap Lock),把本不该参与竞争的记录也锁住了。ThinkPHP 构建的 SQL 如果字段没建索引、或用了函数(如 WHERE DATE(create_time) = '2024-01-01'),就会这样。
- 用
EXPLAIN检查生成的 SQL:重点关注type是否为ALL(全表扫描)、key是否为NULL(未用索引) - WHERE 条件里避免对字段做运算,改用范围查询:
create_time BETWEEN '2024-01-01 00:00:00' AND '2024-01-01 23:59:59' - 高并发更新同一张表时,尽量按主键或唯一索引顺序操作,减少间隙锁重叠;例如批量更新前先
ORDER BY id ASC再遍历
事务嵌套和超时设置不合理放大冲突窗口
ThinkPHP 不支持真正的嵌套事务(PDO 也不支持),Db::transaction() 嵌套只会静默降级为外层事务。如果外层事务长、内层又调用耗时接口(如 HTTP 请求、文件读写),整个事务持有锁的时间就拉得过长,别人等不及就直接报死锁。
- 把事务控制在最小必要范围:只包 DB 操作,HTTP 调用、缓存写入、日志记录全挪到
commit()之后 - 给事务设超时:MySQL 层用
innodb_lock_wait_timeout = 10(秒),PHP 层在Db::transaction()第二个参数传超时秒数(需 ThinkPHP ≥ 6.0.12) - 不要依赖
try/catch重试全部逻辑——捕获到死锁异常后,只重试核心 DB 操作,且加指数退避(如第一次等 10ms,第二次 20ms)
死锁不是代码写错了,而是并发路径上的锁获取顺序出现了不可控交叉。最麻烦的点在于:复现难、日志缺上下文、MySQL 的间隙锁行为又和隔离级别强相关。盯住 INNODB STATUS 里的事务堆栈,比翻 ThinkPHP 源码有用得多。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











