MySQL - 表 'my_table' 没有使用 Lock Tables 进行锁定

58

我试图通过MySQL加载表格,但是出现以下错误:

MySQL 说:表 'cms' 没有使用 LOCK TABLES 锁定

为什么需要锁定表格?我以前从未见过这种情况。是否有任何方法可以解锁?你是否真的需要解锁?

8个回答

88

如果在一个事务中,你锁定了一个表但是想从另一个表进行选择,你必须要么也锁定那个表,要么解锁所有的表。

mysql> LOCK TABLES t1 READ;
mysql> SELECT COUNT(*) FROM t1;
+----------+
| COUNT(*) |
+----------+
|        3 |
+----------+
mysql> SELECT COUNT(*) FROM t2;
ERROR 1100 (HY000): Table 't2' was not locked with LOCK TABLES

20
这是解释这个问题并被接受的答案! - Leonardo Beal
2
很棒的答案。谢谢。我曾尝试从db1锁定表并从db2插入数据。在查询INSERT INTO db1.table SELECT * FROM db2.table之后,我收到了关于未锁定db2.table的错误。我真的不明白为什么会出现这种错误。你解释了一个会话中多个表锁定的问题 - 谢谢! - Jukka Newkampton

52

对我来说最好的解决方案是解锁这些表格。它们被前一个查询锁定,但在达到unlock tables语句之前失败了。

UNLOCK TABLES
SELECT ...

31

http://dev.mysql.com/doc/refman/5.7/en/lock-tables.html


MySQL允许客户端会话显式获取表锁,以便与其他会话合作访问表,或在会话需要独占访问它们的时期防止其他会话修改表。会话只能为自己获取或释放锁。一个会话不能为另一个会话获取锁或释放另一个会话持有的锁。
锁可以用于模拟事务或在更新表时获得更快的速度。这将在本节后面更详细地解释。
LOCK TABLES显式为当前客户端会话获取表锁。表锁可以为基本表或视图获取。您必须具有LOCK TABLES特权,并且对于要锁定的每个对象都必须具有SELECT特权。
对于视图锁定,LOCK TABLES将视图中使用的所有基本表添加到要锁定的表集中,并自动锁定它们。如果您使用LOCK TABLES显式锁定表,则触发器中使用的任何表也会被隐式锁定,如第13.3.5.2节“LOCK TABLES和Triggers”所述。
UNLOCK TABLES显式释放当前会话持有的任何表锁。LOCK TABLES在获取新锁之前隐式释放当前会话持有的任何表锁。
UNLOCK TABLES的另一个用途是释放使用FLUSH TABLES WITH READ LOCK语句获取的全局读锁,该语句使您能够锁定所有数据库中的所有表。请参见第13.7.6.3节“FLUSH Syntax”。(如果您有像Veritas这样的文件系统可以在时间上进行快照,则这是获取备份的非常方便的方法。)

LOCK 和 UNLOCK 的语法

 LOCK TABLES
    tbl_name [[AS] alias] lock_type
    [, tbl_name [[AS] alias] lock_type] ...

lock_type:
    READ [LOCAL]
  | [LOW_PRIORITY] WRITE

例如:

LOCK TABLE t WRITE, t AS t1 READ;

解锁表

 UNLOCK TABLES

17

MySQL文档中与"Table 'my_table' was not locked with LOCK TABLES"消息相关的最重要的一行是:

"在持有这些锁的同时,会话只能访问已锁定的表格而不能访问其它表格" https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html

这意味着如果您在LOCK处于激活状态时尝试访问数据库中的任何其他表格,您将收到错误消息"Table 'my_table' was not locked with LOCK TABLES"

解决方法是将锁应用于在LOCK期间想要访问的所有表格,如下所示。"LOCK TABLES table_1 WRITE, table_2 WRITE"

其中table_1是您真正想要锁定的表格,但您还想在同一过程中访问table_2。

这很令人困惑,因为我只锁定了table_1,但错误消息却告诉我Table 'table_2' was not locked with LOCK TABLES

花费了我一段时间才弄清楚table_2为什么会涉及到。希望这可以帮助遇到同样问题的其他人。


7
在我的情况下,问题是别名。
文档中可以看到:

如果您的语句通过别名引用表格,则必须使用相同的别名锁定该表格。没有指定别名无法锁定表格。

反之,如果您使用别名锁定表格,则必须在语句中使用该别名引用它。

错误的写法:
LOCK TABLE my_table READ;
SELECT * FROM my_table t;
#ERROR 1100: Table 't' was not locked with LOCK TABLES

正确:

LOCK TABLE my_table t READ;
SELECT * FROM my_table t;

2
我遇到了这个问题:
LOCK TABLE <table_a> READ;
LOCK TABLE <table_b> READ;
LOCK TABLE <table_a> WRITE;
LOCK TABLE <table_b> WRITE;

我读到了这个错误信息:表'table_a'没有被锁定

在阅读文档后,我修改了锁定代码如下:

LOCK TABLE <table_a> WRITE, <table_b> WRITE

这对我解决了问题。

锁类型

READ 读锁,不允许写入

WRITE 独占写锁。其他连接无法读取或写入此表


文档注明,您必须一次性包含想要锁定的所有表,当您发出第二个LOCK TABLE语句时,将解除之前已经锁定的表(如果有)。 - fool4jesus
谢谢你提供的这个小贴士! - DJDave

0

我在存储过程中遇到了一个似乎是分叉的进程。这导致了以下错误:

#ERROR 1100: Table 'cached_sales_data' was not locked with LOCK TABLES

关于以下SQL语句:

LOCK TABLES cached_sales_data WRITE, v_sales_data_2 READ;
call refresh_sales_data_now ();
UNLOCK TABLES;

实际上,这是由于refresh_sales_data_now()存储过程中的where子查询引起的。

...
where
  orderdatetime > (select max(orderdatetime)
from
  cached_sales_data)

根据文档,我需要在初始锁定期间创建一个带有别名的第二个READ锁定,然后我可以编写并使用该别名进行二次选择。
LOCK TABLES cached_sales_data WRITE, cached_sales_data as csd READ, v_sales_data_2 READ;
...
where
  orderdatetime > (select max(orderdatetime)
from
  csd)

0
在我的情况下,这个错误是因为我试图从Windows导入数据到Linux:Windows不区分大小写,并且所有表名都是小写的,但是Linux区分大小写,并且具有相同的表名,但是使用大写字母。一旦我改变了源表名的大小写以匹配目标表名,这个错误就不再出现了。以下SO帖子解释了关于mysql在Windows和Linux之间的大小写敏感性问题:MySQL中的表名是否区分大小写?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接