文档首页
MySQL 9.0 参考手册
相关文档 下载本手册
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
手册页 (TGZ) - 258.2Kb
手册页 (Zip) - 365.3Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


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

14.14 锁定函数

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

表 14.19 锁定函数

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

  • GET_LOCK(str,timeout)

    尝试使用 timeout 秒的超时时间获取由字符串 str 给出的名称的锁。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)

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

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

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