本文地址:https://www.askmac.cn/archives/mysql-advisory-lock.html
7.3 协同(Advisory)锁
协同锁没有能力避免来自其它客户端的数据访问,但它们基于一种概念,即所有客户端会使用一个约定的规则来协同使用一种资源。这种约定的规则可以是一个锁名,即一个简单的字符串。当这个名字被锁住,此协同锁认为被获取。那么了解到此锁状态的其它的客户端就会抑制并避免其进行和持有锁的用户具有冲突的操作。
协同锁使用了一套功能函数实现。为了获取锁,使用GET_LOCK()
功能:
第一个参数使用一个字符串定义了被锁的名字,第二个参数是一个以秒为单位的时间值,定义了如果锁无法立刻被获取的情况下,最多等待多长时间。GET_LOCK()
但执行成功则返回1,不过如果时间过后,锁还是未能获取,则返回0,执行中异常报错则返回空值。
获取到协同锁的客户端可以调用RELEASE_LOCK()
功能来释放锁:
如果锁被成功释放,则RELEASE_LOCK()
返回1,如果需要释放的锁是别的客户端锁,则返回0,返回NULL则说明当前名字没有锁。
我们还可以再次通过调用GET_LOCK()
来释放之前的锁,或者直接关闭其和服务端之间的连接也可以达到释放锁的目的。
另外两个可用于查看协同锁状态的功能函数有:
IS_FREE_LOCK(lock_name)
:检查当此名字没有被锁,则返回1,有上锁则返回0,执行报错则返回NULL。IS_USED_LOCK(lock_name)
:返回持有此名字锁的客户端Connection ID,如果此名字未被上锁,则返回NULL。
举例说明协同锁的使用:
假设一个应用运行的会话1和相同应用的会话2互相之间需要对共享资源进行协调操作。它们可以在连接到MySQL服务端后尝试使用协同锁来进行资源协调。在例子中,注意会话在不同时间上的运行:
会话1 | 会话2 |
select get_lock(‘app1_lock’, 1);返回1,锁获取成功,可以继续任务 | |
select get_lock(‘app1_lock, 20);等待20秒后返回0,协同锁获取失败。不能使用之后的资源继续任务。 | |
select get_lock(‘app1_lock, 300);等待300秒。 | |
select release_lock(‘app1_lock’); | |
返回1,锁获取成功,开始继续处理任务。 | |
select is_free_lock(‘app1_lock’);返回0,此协同锁已经被占用。 | |
select release_lock(‘app1_lock’);完成任务,释放锁。 | |
select is_free_lock(‘app1_lock’);返回1,发现此锁未被占用。可以立刻使用get_lock() 来获取它了。 |
注意两个会话之间仅是简单使用了一个公共字符串(例子中“app1_lock”)并调用协同锁相应功能函数来实现协同。
Comment