我们在MySQL中有一个使用InnoDB的表,我们使用的是未提交的事务隔离级别。为什么如图所示的设置@x会获得一个锁?
mysql> set @x = (select userID from users limit 1);
Query OK, 0 rows affected (0.02 sec)
mysql>试图从另一个提示更新此表会导致超时错误:
mysql> update users set userID = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction发布于 2014-05-01 18:09:39
不管它的价值是什么,这种锁定并不局限于READ-UNCOMMITTED
mysql1> show variables like '%isolation%';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
mysql1> BEGIN;
mysql1> SET @x := (SELECT x FROM foo LIMIT 1);
mysql2> UPDATE foo SET x = x+1;
[gets a lock wait]
mysql3> SHOW ENGINE INNODB STATUS;
...
---TRANSACTION 228746, ACTIVE 22 sec
2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 58, OS thread handle 0x7fc262a1c700, query id 8163
192.168.56.1 root cleaning up
TABLE LOCK table `test`.`foo` trx id 228746 lock mode IS
RECORD LOCKS space id 801 page no 3 n bits 80 index `PRIMARY`
of table `test`.`foo` trx id 228746 lock mode S
...正如您所记录的错误错误#67452从select中设置一个变量,在使用read时获得一个锁中所讨论的那样,这种行为可能是由设计造成的。它似乎属于与SELECT语句相同的类别,这些语句的结果用于修改数据,如所描述的情况:
http://dev.mysql.com/doc/refman/5.6/en/innodb-locks-set.html
当在构造
REPLACE INTO t SELECT ... FROM s WHERE ...或UPDATE t ... WHERE col IN (SELECT ... FROM s ...)中使用SELECT时,InnoDB对表s中的行设置共享下键锁。
下一个键锁的原因是为了使SELECT结果更加稳定。也就是说,我们不希望SELECT匹配的行在用于UPDATE或其他数据修改语句时发生更改。
即使tx_isolation是REPEATABLE-READ,这也很重要,因为当SELECT语句作为任何类型的UPDATE的一部分执行时,InnoDB并不支持SELECT语句的REPEATABLE-READ。
关于你的评论:
不管文档是什么,下面是发生的情况:
当您执行普通的SELECT语句时,InnoDB不会在除SERIALIZABLE之外的任何事务隔离中锁定任何东西。
如果您执行SELECT ... LOCK IN SHARE MODE或SELECT ... FOR UPDATE,它当然会锁定。
但是,当您将SELECT作为INSERT INTO...SELECT之类的数据修改语句的一部分,或者在UPDATE的子查询中,或者您在SET @variable := (SELECT...)中找到的时候,它使用共享锁来确保数据在更新过程中不会改变。
文件可能不完整。最好是测试一下。
https://stackoverflow.com/questions/13151837
复制相似问题