mysql数据库的死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当死锁发生时,mysql会检测到该情况并自动回滚其中一个事务,释放其占用的锁资源,让其他事务能够继续执行。

mysql死锁的核心产生原因
mysql的InnoDB引擎默认采用行级锁,死锁的产生需要满足四个必要条件:互斥、占有且等待、不可剥夺、循环等待。在实际业务场景中,最常见的原因是循环等待,也就是多个事务以不同的顺序访问相同的表或行记录,导致锁的获取形成闭环。
比如有两个事务A和B,事务A先锁定表t1的某行,再请求锁定表t2的某行;而事务B先锁定表t2的某行,再请求锁定表t1的某行。如果此时事务A持有t1的行锁等待t2的行锁,事务B持有t2的行锁等待t1的行锁,就会形成死锁。
常见的死锁触发场景示例
假设存在两张表order_info和user_info,两个事务的执行逻辑如下:
-- 事务A执行逻辑 START TRANSACTION; -- 先更新order_info表 UPDATE order_info SET status = 2 WHERE order_id = 1001; -- 再更新user_info表 UPDATE user_info SET balance = balance - 100 WHERE user_id = 50; COMMIT; -- 事务B执行逻辑 START TRANSACTION; -- 先更新user_info表 UPDATE user_info SET balance = balance + 100 WHERE user_id = 50; -- 再更新order_info表 UPDATE order_info SET status = 3 WHERE order_id = 1001; COMMIT;
如果两个事务同时执行,就很可能触发死锁,mysql会回滚其中一个事务并抛出死锁错误。
规范事务访问表的顺序预防死锁
规范事务访问表的顺序是预防循环等待类死锁最直接有效的方法,核心原则是所有事务访问相同的表时,必须保持一致的先后顺序,避免形成锁的获取闭环。
具体实施规范
- 梳理业务中涉及多表操作的事务,制定统一的表访问优先级,比如按照表名字母顺序、业务重要程度排序,所有事务都遵循该顺序访问表。
- 如果事务中需要访问的表数量较多,可提前整理成访问清单,开发时严格按照清单顺序编写SQL,避免顺序混乱。
- 对于关联多表的更新、删除操作,提前确定表的访问顺序,不要随意调整SQL的执行次序。
修改后的示例
将上面的两个事务统一按照order_info表先于user_info表的顺序访问,修改后的事务逻辑如下:
-- 事务A执行逻辑(保持不变) START TRANSACTION; UPDATE order_info SET status = 2 WHERE order_id = 1001; UPDATE user_info SET balance = balance - 100 WHERE user_id = 50; COMMIT; -- 事务B执行逻辑(调整顺序,和事务A保持一致) START TRANSACTION; -- 先更新order_info表,和事务A顺序一致 UPDATE order_info SET status = 3 WHERE order_id = 1001; -- 再更新user_info表 UPDATE user_info SET balance = balance + 100 WHERE user_id = 50; COMMIT;
这样两个事务都会先请求order_info表的行锁,再请求user_info表的行锁,不会出现循环等待的情况,也就不会产生死锁。
其他死锁预防技巧
除了规范事务访问表的顺序,还可以结合以下方法进一步降低死锁发生的概率:
- 尽量缩短事务的执行时间,减少锁的持有时长,避免长事务占用资源。
- 合理设置事务的隔离级别,非必要场景不要使用可重复读以上的高隔离级别,减少锁的范围。
- 给查询条件添加合适的索引,避免无索引导致的表锁升级为行锁范围过大的问题。
- 可以设置合理的锁等待超时时间,通过
innodb_lock_wait_timeout参数控制,避免事务长时间阻塞。
死锁问题排查方法
如果线上还是出现了死锁问题,可以通过mysql提供的工具排查原因:
执行SHOW ENGINE INNODB STATUS命令,在返回结果中可以找到最近的死锁详细信息,包括死锁涉及的事务、执行的SQL、持有的锁和等待的锁等内容,根据这些信息可以定位死锁产生的具体原因,再针对性优化。
注意:规范表访问顺序仅能预防因访问顺序不一致导致的死锁,对于其他原因产生的死锁,需要结合具体场景分析优化。
mysql死锁事务表访问顺序database_lock修改时间:2026-07-19 01:33:24