GET_LOCK([name], 0) 行为和多个 GET_LOCK() 顺序

con*_*cat 5 mysql locking

我从文档中读到,在RELEASE_LOCK从持有锁的连接调用之后分发由许多连接请求的锁的行为是未定义的。我很好奇:假设我有一个p1请求锁定的过程,GET_LOCK("lock", 0);以便对该过程的多次调用不会相互干扰。该过程在终止之前释放锁。我有另一个程序p2使用GET_LOCK("lock", 10);.

假设有大量对 的调用p1,并且在中间的某个地方p2被调用,如下所示:

...
CALL p1();
CALL p1();
CALL p2();
CALL p1();
#lock released here from first p1() call: who gets it?
...
Run Code Online (Sandbox Code Playgroud)

理论上,第二个过程不应该受到太大影响:它等待锁被释放,因为GET_LOCKinp1的超时为 0,p2应该是唯一一个在释放时请求锁的过程。但是,我认为我不能期望这种理想的行为是真实的。GET_LOCK从第一个过程开始,当然会花费一些小但非零的时间,并且由于锁不是按请求顺序分配的,是否有可能将锁传递给连续调用p1p2必须等待?

Rol*_*DBA 4

观察结果

在你的问题中,你说

我从文档中读到,在从持有锁的连接调用 RELEASE_LOCK 之后,分配许多连接请求的锁的行为是未定义的。

你忽略了一些更基本的东西

MySQL 文档明确说明了有关GET_LOCK()的以下内容

负超时值意味着无限超时。

如果多个客户端正在等待锁,则它们获取锁的顺序是不确定的。应用程序不应假设客户端将按照发出锁定请求的顺序获取锁定

该文档没有提及零 (0) 超时值。因此,该行为本身就被简化了。如果获取锁,则立即返回 1。如果未获取锁,则立即返回零 (0)。

你说p2有 10 秒超时(因为你说你正在使用GET_LOCK("lock",10))。

如果您希望p1()暂停执行,则使用非正数将无法实现此目的。

建议

您可能希望在存储过程中执行循环以尝试获取锁,并在锁定尝试之间暂停任意秒数:

SET @seconds_to_pause = 5;
SET @lock_acquired = GET_LOCK('lock',0);
WHILE @lock_acquired = 0 DO
    SET @x = SLEEP(@seconds_to_pause);
    SET @lock_acquired = GET_LOCK('lock',0);
END WHILE;
Run Code Online (Sandbox Code Playgroud)

试一试 !!

您原来的问题

是否有可能将锁传递给 p1 的连续调用,而 p2 必须等待?

如果您没有按照我的建议使用循环来获取锁,那么答案一定是否定的。