菜鸟科技网

mysql解锁命令

  1. 解锁被事务阻塞的行(InnoDB 引擎):这是最常见的“锁”问题,当一个事务没有提交或回滚,它锁定的资源(比如一行数据)会阻塞其他事务的访问。
  2. 解锁被用户手动上锁的表(LOCK TABLES:这是一种较少使用的手动锁定机制。

下面我将详细介绍这两种情况的解锁方法。

mysql解锁命令-图1
(图片来源网络,侵删)

解锁被事务阻塞的行 (InnoDB 行锁)

这种情况通常被称为“死锁”或“等待锁”,但实际上更常见的是一个长事务阻塞了其他所有后续事务,解决这个问题的关键在于找到并结束(KILL)那个持有锁的、长时间运行的事务

第 1 步:找到持有锁的会话(Session)

你需要查询 information_schema 数据库来找出正在持有锁的会话,最常用的查询是 innodb_trxinnodb_locks

查询 1:查看当前正在运行的事务

-- 查看当前所有正在运行的事务,重点关注事务ID、执行时间、状态等
SELECT 
    trx_id,
    trx_state,
    trx_started,
    trx_requested_lock_id,
    trx_wait_started,
    trx_mysql_thread_id AS session_id,
    trx_query 
FROM 
    information_schema.innodb_trx;

查询 2:查看正在等待锁的会话

mysql解锁命令-图2
(图片来源网络,侵删)
-- 查看哪些会话正在等待锁,以及它们在等待什么
SELECT 
    r.trx_id AS waiting_trx_id,
    r.trx_mysql_thread_id AS waiting_thread,
    r.trx_query AS waiting_query,
    b.trx_id AS blocking_trx_id,
    b.trx_mysql_thread_id AS blocking_thread,
    b.trx_query AS blocking_query
FROM 
    information_schema.innodb_lock_waits w
JOIN 
    information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
JOIN 
    information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id;

查询 3:查看所有会话的详细信息(推荐)

这个查询非常全面,能帮你快速定位问题会话。

SELECT
    r.trx_id AS waiting_trx_id,
    r.trx_mysql_thread_id AS waiting_thread_id,
    r.trx_query AS waiting_query,
    b.trx_id AS blocking_trx_id,
    b.trx_mysql_thread_id AS blocking_thread_id,
    b.trx_query AS blocking_query,
    l.lock_table,
    l.lock_index,
    l.lock_type,
    l.lock_mode
FROM
    information_schema.innodb_lock_waits w
JOIN
    information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
JOIN
    information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id
JOIN
    information_schema.innodb_locks l ON l.lock_trx_id = w.blocking_trx_id;

从以上查询结果中,你需要记下 blocking_thread_id(或 trx_mysql_thread_id)的值,这就是导致阻塞的会话ID。

第 2 步:结束持有锁的会话

一旦你找到了 blocking_thread_id,就可以使用 KILL 命令来强制终止这个会话,这会立即回滚该会话中的所有未提交事务,从而释放所有锁。

mysql解锁命令-图3
(图片来源网络,侵删)
-- 将 '12345' 替换为你找到的 blocking_thread_id
KILL 12345;

⚠️ 重要警告:

  • 数据丢失风险KILL 命令会立即终止会话,该会话中所有未提交的更改(INSERT, UPDATE, DELETE)都将被回滚,这可能导致数据不一致,尤其是在应用程序中。
  • 谨慎操作:在生产环境中执行 KILL 命令前,请务必确认该会话确实是一个“流氓”会话,并且终止它带来的负面影响小于让它继续阻塞整个系统。
  • 先备份:如果可能,先通知相关业务人员,或者在业务低峰期执行。

解锁被手动锁定的表 (LOCK TABLES)

这是一种比较老旧的锁定方式,现代应用中很少使用,当一个会话执行了 LOCK TABLES 命令后,它会锁定指定的表,直到它执行 UNLOCK TABLES 或会话结束。

第 1 步:找到持有表锁的会话

-- 查看当前所有持有表锁的会话
SELECT 
    id,
    db,
    user,
    host,
    command,
    time,
    state,
    info
FROM 
    information_schema.processlist
WHERE 
    command = 'Locked';

或者更通用的查询:

SELECT 
    id,
    db,
    user,
    host,
    command,
    time,
    state,
    info
FROM 
    information_schema.processlist
WHERE 
    state = 'Locked' OR command = 'Locked';

记下查询结果中的 id 列,这就是持有表锁的会话ID。

第 2 步:解锁表

你有两种方法来解锁:

方法 A:让持有锁的会话自己解锁(推荐)

这是最安全的方法,联系该会话对应的用户或应用程序,让它执行以下命令:

UNLOCK TABLES;

方法 B:强制终止持有锁的会话

如果无法联系到该会话,或者它已经卡死,可以像处理行锁一样,使用 KILL 命令强制结束它。

-- 将 '12345' 替换为你找到的会话 ID
KILL 12345;

同样,KILL 命令会终止会话并自动释放其持有的所有表锁。


总结与最佳实践

锁类型 原因 查找方法 解锁方法
InnoDB 行锁 事务未提交,阻塞其他事务 查询 information_schema.innodb_trxinnodb_lock_waits KILL [blocking_thread_id]
LOCK TABLES 表锁 会话手动锁定表,未释放 查询 information_schema.processlist UNLOCK TABLESKILL [session_id]

最佳实践:如何避免锁问题?

  1. 保持事务简短:事务中的代码执行时间越短越好,获取锁后尽快提交或回滚。
  2. 按固定顺序访问表:如果多个事务需要访问相同的几张表,确保它们以相同的顺序进行,可以大大降低死锁的概率。
  3. 设置合理的隔离级别:根据业务需求选择合适的隔离级别(如 READ COMMITTEDREPEATABLE READ)。READ COMMITTED 能减少锁的持有时间。
  4. 使用乐观锁:对于读多写少的场景,可以考虑使用版本号(如 version 字段)等乐观锁机制,而不是直接使用悲观锁。
  5. 应用层重试机制:对于偶发的锁等待,可以在应用程序中实现自动重试逻辑,而不是立即报错。
  6. 监控长事务:定期监控 information_schema.innodb_trx,发现长时间运行的事务应及时处理。
分享:
扫描分享到社交APP
上一篇
下一篇