MySQL 通过 kill process 解决死锁
·
一、死锁基础认知
1.1 什么是 MySQL 死锁
死锁是指两个或多个事务互相等待对方持有的锁资源,导致所有事务都无法继续执行的阻塞状态。仅 InnoDB 存储引擎会出现死锁(支持行锁),MyISAM(表锁)因锁粒度大且不支持事务,几乎不会产生死锁。
1.2 死锁产生的 4 个必要条件(缺一不可)
- 互斥条件:锁资源只能被一个事务独占,无法共享;
- 请求与保持条件:事务已持有部分锁,又请求其他事务持有的锁;
- 不可剥夺条件:事务持有的锁不能被强制剥夺,只能主动释放;
- 循环等待条件:多个事务形成锁资源的循环等待链(A 等 B 的锁,B 等 A 的锁)。
1.3 死锁的典型表现
- 事务执行长时间卡住,无响应;
- 应用端抛出
Deadlock found when trying to get lock; try restarting transaction错误; - 通过
SHOW ENGINE INNODB STATUS可查询到死锁详细日志。
二、kill process 解决死锁的核心逻辑
kill process是解决死锁的应急手段,核心原理是:终止死锁链中持有关键锁资源的事务进程,打破 “循环等待条件”,释放被占用的锁资源,让其他事务恢复执行。
注意:InnoDB 默认开启死锁检测(
innodb_deadlock_detect=ON),会自动回滚 “代价最小” 的事务(如修改行数最少)来解除死锁;仅当死锁检测失效、未触发,或需要手动干预时,才需执行 kill 操作。
三、实操步骤:定位死锁 + kill 进程
3.1 步骤 1:精准定位死锁相关进程(2 种核心方法)
方法 1:查看 InnoDB 死锁日志(最精准)
通过该命令可直接获取死锁的事务 ID、锁资源、对应的线程 ID,是定位死锁的首选方式:
SHOW ENGINE INNODB STATUS;
关键日志片段解析:
LATEST DETECTED DEADLOCK
------------------------
2026-01-27 10:00:00 0x7f8b12345678
*** (1) TRANSACTION:
TRANSACTION 12345, ACTIVE 10 sec updating
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1128, 1 row lock(s)
MySQL thread id 100, OS thread id 12345, query id 789 localhost root updating
UPDATE t_order SET status=2 WHERE id=1; -- 事务1执行的SQL
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 123 page no 45 n bits 72 index PRIMARY of table `test`.`t_order` trx id 12345 lock_mode X waiting
*** (2) TRANSACTION:
TRANSACTION 12346, ACTIVE 15 sec updating
mysql tables in use 1, locked 1
2 lock struct(s), heap size 1128, 1 row lock(s)
MySQL thread id 101, OS thread id 12346, query id 790 localhost root updating
UPDATE t_order SET status=1 WHERE id=2; -- 事务2执行的SQL
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 123 page no 45 n bits 72 index PRIMARY of table `test`.`t_order` trx id 12346 lock_mode X
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 123 page no 46 n bits 72 index PRIMARY of table `test`.`t_order` trx id 12346 lock_mode X waiting
*** WE ROLL BACK TRANSACTION 12345 -- InnoDB自动回滚事务1(线程ID 100)
从日志中可提取核心信息:
- 死锁涉及线程 ID(MySQL thread id):100、101;
- 自动回滚的事务:trx id 12345(对应线程 100);
- 死锁原因:两个事务互相等待对方持有的行锁。
方法 2:查看所有活跃进程(筛选锁等待进程)
-- 查看所有进程,重点关注Command=Lock wait、Time值大的进程
SHOW PROCESSLIST;
关键字段说明:
Id:进程 / 线程 ID(kill 操作的核心参数);Command:进程状态(Sleep/Query/Lock wait/Updating 等);Time:进程运行时长(秒),锁等待进程通常 Time 值较大;Info:进程执行的 SQL 语句,可定位具体业务操作。
筛选锁等待进程(精准查询):
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST
WHERE Command = 'Lock wait' AND Time > 10; -- 筛选等待超10秒的进程
3.2 步骤 2:执行 kill process 终止死锁进程
核心语法
-- 基础语法:kill指定线程ID
KILL [CONNECTION|QUERY] 线程ID;
KILL CONNECTION(默认):终止进程的所有操作,关闭客户端连接(推荐);KILL QUERY:仅终止进程当前执行的 SQL,保留连接(仅适用于临时终止慢查询)。
实操示例
-- 1. 定位到阻塞的线程ID为101
-- 2. 执行kill操作(终止该线程,释放锁资源)
KILL 101;
-- 3. 验证:查看进程是否已被终止
SHOW PROCESSLIST WHERE Id = 101; -- 无结果则说明kill成功
四、kill process 的关键注意事项
4.1 操作风险(必须规避)
- kill 的是 “线程 ID” 而非 “事务 ID”:
SHOW PROCESSLIST的Id是线程 ID,INNODB_TRX的trx_id是事务 ID,不可混淆; - 数据一致性风险:被 kill 的事务会被 InnoDB 自动回滚,需确认该事务未执行核心业务(如支付、订单状态更新);
- 避免 kill 核心进程:不要 kill 系统进程(如 Command=Daemon)、数据库主进程,否则可能导致 MySQL 服务异常;
- 高并发场景慎用:kill 操作可能引发连锁反应(如事务回滚耗时、锁资源释放延迟),建议低峰期操作。
4.2 操作建议
- 优先 kill “阻塞方” 进程:通过
INNODB_LOCK_WAITS找到blocking_thread_id,kill 阻塞进程比 kill 等待进程更高效; - 先记录日志再 kill:kill 前执行
SHOW ENGINE INNODB STATUS、SHOW PROCESSLIST并保存结果,便于后续分析死锁原因; - kill 后验证效果:执行 kill 后,查看应用端是否恢复、锁等待进程是否消失。
五、死锁的根本解决:预防(比 kill 更重要)
kill 只是应急手段,要从根源避免死锁,需优化锁使用逻辑:
- 统一锁申请顺序:所有事务按相同的顺序申请锁(如先更新 t_order 表,再更新 t_order_item 表),打破 “循环等待”;
- 缩小锁粒度:尽量使用行锁(InnoDB),避免表锁;减少事务中操作的行数,缩短锁持有时间;
- 控制事务大小:将大事务拆分为小事务,减少锁资源的持有时长;
- 设置锁等待超时:通过
innodb_lock_wait_timeout(默认 50 秒)设置锁等待超时,超时后事务自动回滚,避免永久阻塞; - 开启死锁检测:确保
innodb_deadlock_detect=ON(默认开启),让 InnoDB 自动检测并解除死锁; - 避免长时间事务:事务中不要包含耗时操作(如 RPC 调用、文件 IO),减少锁持有时间。
总结
- 核心逻辑:
kill process通过终止死锁链中的阻塞线程,释放锁资源,打破死锁的 “循环等待条件”,是解决死锁的应急方案; - 实操关键:先通过
SHOW ENGINE INNODB STATUS/INNODB_LOCK_WAITS定位阻塞线程 ID,再执行KILL 线程ID,优先 kill 阻塞方; - 核心原则:kill 只是临时解决手段,根源在于统一锁申请顺序、缩小锁粒度、控制事务大小,从设计上预防死锁。
GitFlowPlus分支管理插件
https://plugins.jetbrains.com/plugin/14056-gitflowplus
更多推荐


所有评论(0)