10bet网址
MySQL 8.0参考手册
相关的文档10bet官方网站 本手册下载
PDF (Ltr)- 41.6 mb
PDF (A4)- 41.7 mb
手册页(TGZ)- 262.5 kb
手册页(邮政编码)- 372.6 kb
信息(Gzip)- 4.0 mb
信息(邮政编码)- 4.0 mb
本手册节选

13.3.6 LOCK TABLES和UNLOCK TABLES语句

锁表tbl_name[[是]别名lock_type[,tbl_name[[是]别名lock_type)……lock_type: {read [local] | [low_priority] write}解锁表

MySQL允许客户端会话显式地获取表锁,以便与其他会话合作访问表,或者防止其他会话在会话需要独占访问表期间修改表。会话只能为自己获取或释放锁。一个会话不能为另一个会话获取锁,也不能释放另一个会话持有的锁。

锁可以用来模拟事务,或者在更新表时提高速度。这将在表锁定限制和条件

锁表显式地为当前客户端会话获取表锁。可以为基表或视图获取表锁。你必须有锁表特权,选择每个被锁定对象的特权。

为视图锁定,锁表将视图中使用的所有基表添加到要锁定的表集中,并自动锁定它们。对于任何被锁定视图的底层表,锁表检查视图定义器(forSQL安全定义者视图)或调用程序(对于所有视图)对表具有适当的特权。

如果显式地锁定表锁表,触发器中使用的任何表也会隐式锁定,如中所述锁表和触发器

如果显式地锁定表锁表,任何与外键约束相关的表都将隐式打开和锁定。对于外键检查,共享只读锁(锁表读)在相关表上。对于级联更新,无共享写锁(锁表写)被取到与操作相关的表上。

打开表显式释放当前会话持有的任何表锁。锁表在获取新锁之前隐式释放当前会话持有的任何表锁。

另一个使用打开表方法获取的全局读锁是否释放用读锁刷新表语句,该语句使您能够锁定所有数据库中的所有表。看到第13.7.8.3节," FLUSH语句".(如果您有一个文件系统,如Veritas,可以及时进行快照,这是一种非常方便的获取备份的方法。)

表锁只保护其他会话不适当的读或写。举行会议的会议Lock可以执行表级操作,例如删除表截断表.举行锁,删除表而且截断表禁止操作。

下面的讨论只适用于非临时表。锁表是否允许(但被忽略)临时表格该表可以由创建它的会话自由访问,而不管其他锁是否有效。不需要锁,因为没有其他会话可以看到该表。

表锁获取

要获取当前会话中的表锁,请使用锁表语句,该语句获取元数据锁(参见第8.11.4节“元数据锁定”).

有以下几种锁类型:

读(本地)锁:

  • 持有锁的会话可以读表(但不能写表)。

  • 多个会话可以获得一个同时锁定表。

  • 其他会话可以读取表而不显式地获取锁。

  • 当地的修饰符可以不冲突插入语句(并发插入),以便在持有锁时执行。(见第8.11.3节“并发插入”)。然而,阅读当地如果您打算在持有锁的同时使用服务器外部的进程操作数据库,则不能使用该选项。为InnoDB表,阅读当地

(LOW_PRIORITY)写锁:

  • 持有锁的会话可以读写表。

  • 只有持有锁的会话才能访问该表。在释放锁之前,没有其他会话可以访问它。

  • 其他会话对表的锁定请求被阻塞锁举行。

  • LOW_PRIORITY修饰符无效。在以前版本的MySQL中,它会影响锁定行为,但现在不再是这样了。现在已弃用,使用它会产生警告。使用没有LOW_PRIORITY代替。

锁的优先级通常高于锁定,以确保尽快处理更新。这意味着如果一个会话获得一个锁定,然后另一个会话请求锁,随后锁请求等待直到请求的会话Lock获得了锁并释放了锁。的小值可能会出现此策略的异常max_write_lock_count系统变量;看到第8.11.4节“元数据锁定”)。

如果锁表语句必须等待,因为任何表上的其他会话持有锁,它会阻塞,直到所有锁都被获取。

需要锁的会话必须在一个单独的会话中获得它需要的所有锁锁表声明。当获得的锁被持有时,会话只能访问锁定的表。例如,在以下语句序列中,尝试访问时会发生错误t2因为它没有锁在锁表声明:

mysql>锁表SELECT COUNT(*) FROM t1;+----------+ | 数 (*) | +----------+ | 3  | +----------+ 从t2 mysql > SELECT COUNT (*);错误1100 (HY000):表“t2”没有锁定锁定表

INFORMATION_SCHEMA数据库是一个例外。可以在不显式锁定的情况下访问它们,甚至在会话持有通过获取的表锁时也是如此锁表

不能在一个查询中使用相同的名称多次引用一个锁定表。使用别名代替,并为表和每个别名获得一个单独的锁:

mysql>锁表t写,t为t1读mysql> INSERT INTO t SELECT * FROM t;Table 't' was not locked with LOCK TABLES mysql> INSERT INTO t SELECT * FROM t AS t1;

错误发生在第一个插入因为对于一个锁定的表,有两个对相同名称的引用。第二个插入成功是因为对表的引用使用了不同的名称。

如果语句通过别名引用表,则必须使用相同的别名锁定表。如果不指定别名,锁定表是无效的:

mysql>锁表SELECT * FROM t AS myalias;错误1100:表“myalias”没有被锁定

相反,如果你使用别名锁定一个表,你必须在你的语句中使用该别名引用它:

mysql>锁表mysql> SELECT * FROM;Table 't' was not locked with LOCK TABLES mysql> SELECT * FROM t AS myalias;

表锁释放

当会话持有的表锁被释放时,它们将同时被释放。会话可以显式释放锁,也可以在某些条件下隐式释放锁。

  • 会话可以显式地释放它的锁打开表

  • 如果一个会话发出一个锁表语句在已经持有锁的情况下获取锁,则在授予新锁之前隐式释放其现有锁。

  • 如果一个会话开始一个事务(例如,与开始事务),一个隐式打开表,这将导致释放现有的锁。(有关表锁定和事务之间交互的其他信息,请参见表锁定和事务的交互)。

如果客户机会话的连接终止(正常或异常),服务器将隐式释放会话持有的所有表锁(事务性和非事务性)。如果客户端重新连接,锁将不再有效。此外,如果客户端有一个活动的事务,服务器将在断开连接时回滚该事务,如果发生重新连接,则新会话将开始并启用自动提交。因此,客户端可能希望禁用自动重新连接。在自动重新连接生效的情况下,如果发生重新连接,但丢失了任何表锁或当前事务,则不会通知客户机。在禁用自动重新连接的情况下,如果连接断开,发出的下一条语句将出错。客户机可以检测到错误并采取适当的操作,如重新获取锁或重新执行事务。看到自动重新连接控制

请注意

如果你使用ALTER TABLE在上锁的桌子上,它可能会变成无锁的。例如,如果你尝试第二次ALTER TABLE操作时,结果可能是错误表的tbl_name'不是锁表.要处理这个问题,请在第二次修改之前再次锁定表。另请参阅B.3.6.1节“ALTER TABLE的问题”

表锁定和事务的交互

锁表而且打开表与事务的使用互动如下:

  • 锁表不是事务安全的,并且在试图锁定表之前隐式提交任何活动事务。

  • 打开表隐式提交任何活动事务,但只有在锁表已经被用来获取表锁。例如,在下面这组语句中,打开表释放全局读锁但不提交事务,因为没有表锁生效:

    用读锁刷新表;开始事务;选择……;打开表;
  • 开始事务(例如,与开始事务)隐式提交任何当前事务并释放现有的表锁。

  • 用读锁刷新表获取全局读锁而不是表锁,因此它不受制于与锁表而且打开表关于表锁定和隐式提交。例如,开始事务不释放全局读锁。看到第13.7.8.3节," FLUSH语句"

  • 其他隐式导致事务提交的语句不会释放现有的表锁。有关此类语句的列表,请参见第13.3.3节“导致隐式提交的语句”

  • 正确的使用方法锁表而且打开表使用事务表,例如InnoDB表,是用来开始交易的SET autocommit = 0(不开始事务)紧随其后锁表和不要打电话打开表直到您显式地提交事务。例如,如果您需要写入表t1从表格中读取t2,你可以这样做:

    设置自动提交= 0;锁表t1写,t2读,…...在这里对表t1和t2做一些事情……提交;打开表;

    当你打电话锁表InnoDBinternal使用它自己的表锁,MySQL使用它自己的表锁。InnoDB在下一次提交时释放它的内部表锁,但是MySQL要释放它的表锁,你必须调用打开表.你不应该自动提交= 1,因为这样InnoDB的调用后立即释放其内部表锁锁表,死锁很容易发生。InnoDB是否根本没有获得内部表锁自动提交= 1,以帮助旧应用程序避免不必要的死锁。

  • 回滚不释放表锁。

锁表和触发器

如果显式地锁定表锁表,触发器中使用的任何表也会被隐式锁定:

  • 类显式获取锁的时间与获取锁的时间相同锁表声明。

  • 触发器中使用的表上的锁取决于该表是否仅用于读取。如果是这样,一个读锁就足够了。否则,将使用写锁。

  • 如果表被显式锁定以用于读取锁表,但是需要锁定以进行写入,因为它可能在触发器中被修改,因此使用的是写锁而不是读锁。(也就是说,由于表在触发器中出现而需要的隐式写锁会导致表的显式读锁请求转换为写锁请求。)

假设您锁定了两个表,t1而且t2,使用以下语句:

锁表t1写,t2读;

如果t1t2如果有任何触发器,那么在触发器中使用的表也会被锁定。假设t1触发器的定义如下:

CREATE TRIGGER t1_a_ins AFTER INSERT ON t1 FOR EACH ROW BEGIN UPDATE t4 SET count = count+1 WHERE id = NEW。id AND EXISTS (SELECT a FROM t3);INSERT INTO t2 VALUES(1,2);结束;

的结果锁表声明是t1而且t2被锁定是因为它们出现在对账单中,然后t3而且t4被锁定是因为它们在触发器中使用:

  • t1是否锁定用于写入锁请求。

  • t2为写入锁定,即使请求是针对锁。这是因为t2被插入到触发器中,因此请求转换为请求。

  • t3锁定用于读取,因为它只从触发器内部读取。

  • t4为写入锁定,因为它可能在触发器内更新。

表锁定限制和条件

你可以安全地使用杀了终止正在等待表锁的会话。看到第13.7.8.4节,“KILL语句”

锁表而且打开表不能在存储程序中使用。

performance_schema数据库无法锁定锁表,除了setup_xxx表。

当a锁表声明生效:创建表创建表……就像创建视图删除视图,以及关于存储函数和过程和事件的DDL语句。

中的系统表对于某些操作mysql必须访问数据库。例如,帮助语句需要服务器端帮助表的内容,并且CONVERT_TZ ()可能需要读取时区表。服务器隐式地锁定系统表以便在必要时读取,因此您不需要显式地锁定它们。这些表的处理方法如下:

mysql。help_category mysql。help_keyword mysql。help_relation mysql。help_topic mysql。time_zone mysql。time_zone_leap_second mysql。time_zone_name mysql。time_zone_transition mysql.time_zone_transition_type

如果你想显式地放置a锁定任何一个表锁表语句中,表必须是唯一锁定的表;没有其他表可以用相同的语句锁定。

通常,您不需要锁定表,因为所有表都是单表更新语句是原子;任何其他会话都不能干扰其他正在执行的SQL语句。然而,在一些情况下,锁定表可能会提供优势:

  • 如果你要在一组上运行许多操作MyISAM表,锁定将要使用的表要快得多。锁定MyISAM表的插入、更新或删除速度加快,因为MySQL不会刷新锁定表的键缓存,直到打开表被称为。通常,键缓存在每个SQL语句之后被刷新。

    锁定表的缺点是没有会话可以更新表(包括持有锁的表),没有会话可以访问除了拿着锁的那张表。

  • 如果为非事务性存储引擎使用表,则必须使用锁表如果您想确保没有其他会话修改a之间的表选择和一个更新.这里显示的示例需要锁表执行安全:

    锁表反读,客户写;SELECT SUM(value) FROM trans WHERE customer_id=some_id;更新客户SET total_value=sum_from_previous_statementcustomer_id =some_id;打开表;

    没有锁表时,另一个会话可能会在反式表之间执行选择而且更新语句。

你可以避免使用锁表在许多情况下,通过使用相对更新(更新客户组价值价值+new_value)或LAST_INSERT_ID ()函数。

在某些情况下,还可以通过使用用户级建议锁函数来避免锁定表GET_LOCK ()而且RELEASE_LOCK ().这些锁保存在服务器的散列表中,并使用pthread_mutex_lock ()而且pthread_mutex_unlock ()高速度。看到第12.15节,“锁定功能”

看到第8.11.1节“内部锁定方法”,以了解有关锁定策略的更多信息。