扩展 MySQL 8.0  / 第 6 章 向 MySQL 添加函数  /  12.15 锁定函数

12.15 锁定函数

本节描述用于操作用户级锁的函数。

表 12.19 锁定功能

姓名 描述
GET_LOCK() 获取命名锁
IS_FREE_LOCK() 命名锁是否空闲
IS_USED_LOCK() 命名锁是否正在使用;如果为真,则返回连接标识符
RELEASE_ALL_LOCKS() 释放所有当前命名锁
RELEASE_LOCK() 释放命名锁

  • GET_LOCK(str,timeout)

    尝试使用 string 给定的名称获取锁 str,使用超时 timeout秒数。负值 timeout意味着无限超时。锁是独占的。当由一个会话持有时,其他会话无法获得同名锁。

    1如果成功获得锁,0如果尝试超时(例如,因为另一个客户端先前已锁定该名称),或者NULL是否发生错误(例如内存不足或线程被 mysqladmin kill 杀死), 则 返回。

    当您的会话终止(正常或异常)时GET_LOCK() ,通过执行或隐式释放 获得的锁。 当事务提交或回滚时,不会释放使用 RELEASE_LOCK()获得的锁。GET_LOCK()

    在 MySQL 5.7 中,GET_LOCK()使用元数据锁定 (MDL) 子系统重新实现,并扩展了其功能。可以同时获取多个锁,GET_LOCK() 并且不会释放任何现有的锁。

    一个给定的会话甚至可以为同一个名称获取多个锁。在获取会话释放其对该名称的所有锁定之前,其他会话无法获取具有该名称的锁。

    作为 MDL 重新实现的结果,获得的唯一命名锁GET_LOCK()出现在 Performance Schema metadata_locks表中。列 OBJECT_TYPE表示USER LEVEL LOCKOBJECT_NAME列表示锁名称。在为同一个名称获取多个锁的情况下,只有该名称的第一个锁会在metadata_locks表中注册一行 。名称的后续锁会增加锁中的计数器,但不会获取额外的元数据锁。metadata_locks当名称上的最后一个锁实例被释放时,锁所在 的 行被删除。

    获取多个锁的能力意味着客户端之间存在死锁的可能性。发生这种情况时,服务器会选择一个调用者并终止其锁定获取请求并 ER_USER_LOCK_DEADLOCK报错。此错误不会导致事务回滚。

    在 MySQL 5.7 之前,只能获取一个并发锁并GET_LOCK() 释放任何现有锁。从以下示例可以看出 MySQL 5.7 中锁获取行为的差异。假设您执行这些语句:

    SELECT GET_LOCK('lock1',10);
    SELECT GET_LOCK('lock2',10);
    SELECT RELEASE_LOCK('lock2');
    SELECT RELEASE_LOCK('lock1');

    在 MySQL 5.7 或更高版本中,第二个 GET_LOCK()获取第二个锁并且两个RELEASE_LOCK() 调用都返回 1(成功)。在 MySQL 5.7 之前,第二个 GET_LOCK()释放第一个锁 ('lock1')而第二个 RELEASE_LOCK()返回 NULL(failure) 因为没有 'lock1'释放。

    MySQL 5.7 及更高版本强制锁定名称的最大长度为 64 个字符。以前,没有强制执行限制。

    GET_LOCK()可用于实现应用程序锁或模拟记录锁。名称在服务器范围内被锁定。如果一个名称在一个会话中被锁定,GET_LOCK() 阻止另一个会话对同名锁的任何请求。这使同意给定锁名称的客户端能够使用该名称来执行协作咨询锁定。但请注意,它还可以使不在合作客户端集合中的客户端无意或有意地锁定名称,从而防止任何合作客户端锁定该名称。减少这种可能性的一种方法是使用特定于数据库或特定于应用程序的锁名称。例如,使用 db_name.str或 形式的锁名称app_name.str

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

    GET_LOCK()对于基于语句的复制是不安全的。如果您在 binlog_format设置为 时使用此功能,则会记录一条警告STATEMENT

    由于GET_LOCK()仅在单个mysqld上建立锁,因此它不适合与 NDB Cluster 一起使用,NDB Cluster 无法在多个 MySQL 服务器上强制执行 SQL 锁。有关更多信息,请参阅 第 21.2.7.10 节,“与多个 NDB Cluster 节点相关的限制”

    警告

    有了获取多个命名锁的能力,一条语句就可以获取大量的锁。例如:

    INSERT INTO ... SELECT GET_LOCK(t1.col_name) FROM t1;

    这些类型的陈述可能会产生某些不利影响。例如,如果语句中途失败并回滚,则在失败点之前获取的锁仍然存在。如果意图是在插入的行和获取的锁之间建立对应关系,则不满足该意图。此外,如果按特定顺序授予锁很重要,请注意结果集顺序可能因优化器选择的执行计划而异。由于这些原因,最好将应用程序限制为每个语句调用一次锁获取。

    不同的锁定接口可用作插件服务或一组可加载功能。这个接口提供了锁命名空间和不同的读写锁,不像 GET_LOCK()and相关函数提供的接口。有关详细信息,请参阅第 5.5.6.1 节,“锁定服务”

  • IS_FREE_LOCK(str)

    检查命名的锁是否str 可以免费使用(即未锁定)。返回 1锁是否空闲(没有人在使用锁)、0锁是否正在使用以及 NULL是否发生错误(例如不正确的参数)。

    此函数对于基于语句的复制是不安全的。如果您在 binlog_format设置为 时使用此功能,则会记录一条警告STATEMENT

  • IS_USED_LOCK(str)

    检查指定的锁是否str 正在使用(即锁定)。如果是,它返回持有锁的客户端会话的连接标识符。否则,它返回NULL

    此函数对于基于语句的复制是不安全的。如果您在 binlog_format设置为 时使用此功能,则会记录一条警告STATEMENT

  • RELEASE_ALL_LOCKS()

    释放当前会话持有的所有命名锁并返回释放的锁数(如果没有则为 0)

    此函数对于基于语句的复制是不安全的。如果您在 binlog_format设置为 时使用此功能,则会记录一条警告STATEMENT

  • RELEASE_LOCK(str)

    str释放以获得 的字符串命名的锁 GET_LOCK()。返回 1锁是否被释放, 0如果锁不是由这个线程建立的(在这种情况下锁没有被释放), NULL如果命名的锁不存在。GET_LOCK()如果锁从未通过调用获得或之前已被释放,则 锁不存在 。

    DO语句与 一起使用很方便RELEASE_LOCK()。请参阅 第 13.2.3 节,“DO 语句”

    此函数对于基于语句的复制是不安全的。如果您在 binlog_format设置为 时使用此功能,则会记录一条警告STATEMENT