MySQL IS_USED_LOCK() 函数使用指南
MySQL IS_USED_LOCK() 是一个非阻塞的锁状态检测函数。它用于探查指定名称的咨询锁当前是否已被某个数据库连接持有,并在已被持有的情况下返回占用者的连接线程标识符(Connection ID)。
在分布式系统死锁排查、集群健康巡检以及运维审计场景中,直接通过 IS_USED_LOCK() 能够快速定位到底是哪一个活跃客户端线程卡住了关键业务锁,无需盲目重启服务。
MySQL IS_USED_LOCK() 语法
这里是 MySQL IS_USED_LOCK() 函数的标准语法:
IS_USED_LOCK(str)
参数
str- 必需的。拟探查的目标命名锁名称字符串。
返回值
MySQL IS_USED_LOCK() 返回一个整数或 NULL:
- 若目标锁当前正被某一连接占用:返回持有该锁的会话连接标识符(即
CONNECTION_ID()对应的整数值)。 - 若目标锁当前未被任何人使用(完全空闲):返回
NULL。
MySQL IS_USED_LOCK() 示例
以下示例演示如何探测锁所有权并结合系统表定位阻塞源头。
检查锁的占用状态
在 Session 1 中建立并持有锁:
-- Session 1 (查看自身 connection_id 为 14)
SELECT CONNECTION_ID();
SELECT GET_LOCK('export_excel_mutex', 5);
切换到 Session 2 或运维巡检终端探查该锁:
SELECT IS_USED_LOCK('export_excel_mutex') AS holding_connection_id;
输出:
+-----------------------+
| holding_connection_id |
+-----------------------+
| 14 |
+-----------------------+如果锁未被占用:
SELECT IS_USED_LOCK('an_idle_task_lock') AS holding_connection_id;
输出:
+-----------------------+
| holding_connection_id |
+-----------------------+
| NULL |
+-----------------------+结合 PROCESSLIST 快速定位持锁客户端来源
当发现某一锁长时间不释放时,可以通过返回的连接 ID 联合 information_schema.processlist 追查该客户端的 IP、执行时长与当前状态:
SELECT
p.id AS conn_id,
p.user,
p.host,
p.db,
p.command,
p.time AS running_seconds,
p.state
FROM information_schema.processlist p
WHERE p.id = IS_USED_LOCK('export_excel_mutex');
输出:
+---------+------+--------------------+---------+---------+-----------------+-------+
| conn_id | user | host | db | command | running_seconds | state |
+---------+------+--------------------+---------+---------+-----------------+-------+
| 14 | app | 192.168.1.50:52410 | shop_db | Sleep | 120 | |
+---------+------+--------------------+---------+---------+-----------------+-------+查询结果直接暴露了位于 192.168.1.50 的客户端处于 Sleep 状态但未归还锁,运维人员可依此采取通知或 KILL 14; 措施。
结论
IS_USED_LOCK()本身纯粹读取锁状态,不会阻塞当前会话,也不会对目标锁加锁。- 可以使用
IS_USED_LOCK(str) = CONNECTION_ID()表达式判断当前会话是否为该锁的主人,从而实现防御式代码重入保护。 - 绝不要用
IS_USED_LOCK() IS NULL来决定随后是否调用GET_LOCK(),因为探查与加锁之间存在非原子性的时间窗口,应当直接调用GET_LOCK(str, timeout)并依据其返回值进行分支控制。