【发布时间】:2014-01-25 08:34:31
【问题描述】:
我已经阅读并测试过 MySQL 的 InnoDB 中的行级锁,但我仍然觉得很难说“我知道 MySQL 中的锁是如何工作的”!
这是我的测试数据:
mysql> select * from lockable;
+----+----+----+
| id | c1 | c2 |
+----+----+----+
| 1 | A | A |
| 2 | A | B |
| 3 | A | C |
| 4 | B | A |
| 5 | B | B |
| 6 | B | C |
| 7 | C | A |
| 8 | C | B |
| 9 | C | C |
+----+----+----+
9 rows in set (0.00 sec)
为了测试 MySQL 关于行级锁的行为,我打开了两个终端并连接到 MySQL。我要把它们命名为mysql1> 和mysql2>。这是我在第一个终端上执行的操作:
mysql1> ROLLBACK;
mysql1> BEGIN;
mysql1> SELECT id, c1, c2 FROM lockable WHERE c1 = "A" FOR UPDATE;
+----+----+----+
| id | c1 | c2 |
+----+----+----+
| 1 | A | A |
| 2 | A | B |
| 3 | A | C |
+----+----+----+
3 rows in set (0.00 sec)
然后在第二个终端上:
mysql2> SELECT * FROM lockable WHERE c1 = "B" FOR UPDATE;
令我惊讶的是,上面的查询会被第一个查询阻止!于是我回滚了第一个终端,重新开始:
mysql1> ROLLBACK;
mysql1> BEGIN;
mysql1> SELECT id, c1, c2 FROM lockable LIMIT 3 FOR UPDATE;
+----+----+----+
| id | c1 | c2 |
+----+----+----+
| 1 | A | A |
| 2 | A | B |
| 3 | A | C |
+----+----+----+
3 rows in set (0.00 sec)
然后在第二个终端上:
mysql2> SELECT * FROM lockable WHERE LIMIT 6,1 FOR UPDATE;
第二个终端又被第一个屏蔽了!是否存在并非表的所有记录都被锁定的情况?如果不是,为什么称为“行级锁定”?
【问题讨论】:
-
不相关但:在标准 SQL 中,双引号仅用于标识符。要指定字符串文字,请使用单引号。
"B"是列名,但'B'是字符串值。 MySQL 接受错误和正确的书写方式,但如果您想使用不同的 DBMS,您应该坚持使用符合标准的方式。关于您的问题:我认为(不确定)您受到 MySQL 的“间隙锁定”的影响,它锁定了其他行,而不仅仅是您请求的行。您可能还想尝试使用真正的update。也许select .. for update的行为有所不同。 -
感谢您的帖子,从现在开始我将尝试使用
'而不是"。 -
顺便说一句:您的示例在 Postgres 和 Oracle 中按预期工作。
-
我也设法让它在 MySQL 中工作。我会尽快发布答案。
标签: mysql innodb rowlocking