哪些记录被MySQL的'SELECT ... FOR UPDATE'锁定

时间:2014-01-25 08:34:31

标签: mysql innodb rowlocking

我已经阅读并测试了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;

第二个终端再次被第一个终端阻止!是否存在未锁定表的所有记录的任何情况?如果不是为什么这称为“行级锁定”?

1 个答案:

答案 0 :(得分:1)

我的问题的答案在MySQL's manual中说:

  

锁定读取,UPDATE或DELETE通常设置记录锁定   在处理SQL时扫描的每个索引记录   言。

因此锁定应用于遍历期间扫描的记录,而不是所有记录。如果未找到索引,则完成全扫描并锁定所有记录。所以我需要在列上设置索引。即使这样,如果在获取目标记录时读取了某些记录,那么它们也会被锁定(即使它们可能最终未被选中)。