文档首页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


MySQL 8.4 参考手册  /  函数和运算符  /  锁定函数

14.14 锁定函数

本节介绍用于操作用户级锁的函数。

表 14.19 锁定函数

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

  • GET_LOCK(str,timeout)

    尝试获取一个名为 str 的锁,超时时间为 timeout 秒。负的 timeout 值表示无限超时。该锁是独占的。当被一个会话持有时,其他会话无法获取相同名称的锁。

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

    使用 GET_LOCK() 获取的锁可以通过执行 RELEASE_LOCK() 显式释放,也可以在会话终止时(正常或异常终止)隐式释放。使用 GET_LOCK() 获取的锁在事务提交或回滚时不会释放。

    GET_LOCK() 是使用元数据锁定 (MDL) 子系统实现的。可以获取多个同时存在的锁,GET_LOCK() 不会释放任何现有的锁。例如,假设您执行以下语句

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

    第二个 GET_LOCK() 会获取第二个锁,并且两个 RELEASE_LOCK() 调用都会返回 1(成功)。

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

    使用 GET_LOCK() 获取的唯一命名的锁会出现在性能模式 metadata_locks 表中。 OBJECT_TYPE 列显示 USER LEVEL LOCKOBJECT_NAME 列指示锁名称。在为 相同 名称获取多个锁的情况下,只有该名称的第一个锁会注册到 metadata_locks 表中。针对该名称的后续锁会增加锁中的计数器,但不会获取额外的元数据锁。当该名称上的最后一个锁实例被释放时,会删除 metadata_locks 表中该锁的条目。

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

    MySQL 对锁名称的长度进行了限制,最大长度为 64 个字符。

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

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

    GET_LOCK() 对基于语句的复制来说是不安全的。如果 binlog_format 设置为 STATEMENT,则在使用此函数时会记录警告。

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

    警告

    在能够获取多个命名锁的情况下,单个语句可能会获取大量锁。例如

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

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

    另一种锁定接口可作为插件服务或一组可加载函数提供。与 GET_LOCK() 及相关函数提供的接口不同,此接口提供锁命名空间以及不同的读锁和写锁。有关详细信息,请参见 第 7.6.9.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)

    释放使用 GET_LOCK() 获取的由字符串 str 命名的锁。如果释放了锁,则返回 1;如果锁不是由当前线程建立的(在这种情况下锁不会被释放),则返回 0;如果命名锁不存在,则返回 NULL。如果锁从未通过调用 GET_LOCK() 获取过或已被释放,则该锁不存在。

    使用 DO 语句可以方便地使用 RELEASE_LOCK()。请参见 第 15.2.3 节,“DO 语句”

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