强制释放 MySQL/MAriaDB 中的用户级锁

Force-release a user-level lock in MySQL/MAriaDB

我的会话管理 (Zebra Session) 使用用户级锁来避免同一会话中两个请求之间的竞争条件。要开始会话,使用 GET_LOCK。关闭会话后,使用RELEASE_LOCK。

MariaDB [planner_20201026]> select GET_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587aaaa', '5');
+-------------------------------------------------------------------+
| GET_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587aaaa', '5') |
+-------------------------------------------------------------------+
|                                                                 1 |
+-------------------------------------------------------------------+
1 row in set (0.000 sec)

MariaDB [planner_20201026]> select  RELEASE_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587aaa');
+-----------------------------------------------------------------+
| RELEASE_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587aaa') |
+-----------------------------------------------------------------+
|                                                            NULL |
+-----------------------------------------------------------------+
1 row in set (0.000 sec)

现在我处于一种情况,因为我还不知道锁没有正确释放的原因。 GET_LOCK 由于超时而完成,RELEASE_LOCK 告诉我它无法释放锁,因为它(根据文档)是由另一个线程建立的:

MariaDB [xyz]> select GET_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587ac8b', '5');
+-------------------------------------------------------------------+
| GET_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587ac8b', '5') |
+-------------------------------------------------------------------+
|                                                                 0 |
+-------------------------------------------------------------------+
1 row in set (5.015 sec)

MariaDB [xyz]> select  RELEASE_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587ac8b');
+------------------------------------------------------------------+
| RELEASE_LOCK('session_ebe210e9b39f1ad3a409763be60efebff587ac8b') |
+------------------------------------------------------------------+
|                                                                0 |
+------------------------------------------------------------------+
1 row in set (0.000 sec)

会话现在或多或少 blocked/useless/doomed,每个请求额外花费 TIMEOUT 秒。

我有没有机会清除那个锁,尤其是在超时之后?

您只能使用 RELEASE_LOCK() 来释放在同一线程中获取的锁。一个线程无权强制另一个线程放弃它的锁。

如果您可以获得锁但任何其他线程都可以单方面强制您释放它,那将是一个非常无用的锁定系统!

解决此问题的一种方法是调用 IS_USED_LOCK() 来告诉您哪个线程持有锁。它 return 是持有者的整数线程 ID,如果锁没有被任何人持有,则为 NULL。

然后如果你有 SUPER 权限,你的线程可以杀死另一个线程,这将迫使它释放它的锁(以及断开那个客户端)。但这是一件非常粗鲁的事情。

我觉得这是 XY Problem。您正在寻找一种强制释放其他线程持有的锁的解决方案,但这是一个糟糕的解决方案,因为它不能解决您的实际问题。

真正的问题是:

Now I am in a situation because of a reason which I do not know yet where the lock was not released properly.

您需要更加认真地考虑这一点并设计一个您不会忘记谁获得了锁的系统。

提示:GET_LOCK(name, 0) 可能有帮助。这 returns 立即(即超时为零秒)。如果能获取到锁,则获取,GET_LOCK的return值为1,如果已经被其他线程持有,则GET_LOCK仍为returns立即,但 return 值为 0,告诉您无法获取它。