8

我们在 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
4

2 回答 2

2

对于它的价值,这种锁定不限于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 Setting a variable from a select 在使用 read uncommitted 时获取锁,这种行为可能是设计使然。它似乎SELECT与其结果用于修改数据的语句属于同一类别,如下所述:

http://dev.mysql.com/doc/refman/5.6/en/innodb-locks-set.html

当在结构中使用 SELECT 时REPLACE INTO t SELECT ... FROM s WHERE ...UPDATE t ... WHERE col IN (SELECT ... FROM s ...)InnoDB 在 table 的行上设置共享的 next-key 锁s

使用 next-key locks 的原因是为了让SELECT结果更稳定。也就是说,我们不希望与 匹配的行在SELECT用于一个UPDATE或其他数据修改语句时发生变化。

即使 tx_isolation 是REPEATABLE-READ,这也很重要,因为 InnoDB 不支持REPEATABLE-READ语句SELECT作为任何类型的UPDATE.


回复您的评论:

无论文档如何,都会发生以下情况:

当您执行普通SELECT语句时,InnoDB 不会在任何事务隔离中锁定任何东西,除了SERIALIZABLE.

如果您执行SELECT ... LOCK IN SHARE MODEor SELECT ... FOR UPDATE,它当然会锁定。

但是,当您SELECT作为数据修改语句的一部分执行时,如INSERT INTO...SELECT或在 a 的子查询中或在 a 中UPDATE找到时SET @variable := (SELECT...),它使用共享锁来确保数据在更新过程中不会更改。

文档可能不完整。更好地测试。

于 2014-05-01T18:09:39.843 回答
0

Your first statement executes a SELECT on the table, therefore the transaction acquires a read lock on one row.

The second transaction tries to acquire a write lock on the same table (on all rows, since there is no WHERE clause), but cannot.

You need to issue a COMMIT (or ROLLBACK) command after the SET @x = (...), so that it releases the read lock.

The above is wrong. I keep this post just because the below comments might be of interest.

于 2012-10-31T13:46:17.313 回答