9

我正在阅读有关 innodb 事务的手册,但我仍然有很多不清楚的东西。例如,我不太了解以下行为:

-- client 1                             -- client 2
mysql> create table simple (col int) 
       engine=innodb; 

mysql> insert into simple values(1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into simple values(2);
Query OK, 1 row affected (0.00 sec)

mysql> select @@tx_isolation;                                                              
+-----------------+                                                                         
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |                                                                         
+-----------------+

mysql> begin;                                    
Query OK, 0 rows affected (0.01 sec)            
                                        mysql> begin;
                                        Query OK, 0 rows affected (0.00 sec)

mysql> update simple set col=10 where col=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

                                         mysql> update simple set col=42 where col=2;
                                         -- blocks

现在,最后一个更新命令(在客户端 2 中)等待。我希望命令能够执行,因为我假设只有第 1 行被锁定。即使客户端 2 中的第二个命令是insert. 谁能描述这个例子背后的锁定背景(锁定的位置和原因)?

4

3 回答 3

10

InnoDB 设置特定类型的锁如下。

  • SELECT ... FROM 是一致读取,读取数据库的快照并且不设置锁,除非事务隔离级别设置为 SERIALIZABLE。对于 SERIALIZABLE 级别,搜索在它遇到的索引记录上设置共享的 next-key 锁。

  • SELECT ... FROM ... LOCK IN SHARE MODE 在搜索遇到的所有索引记录上设置共享的 next-key 锁。

  • 对于搜索遇到的索引记录,SELECT ... FROM ... FOR UPDATE 阻止其他会话执行 SELECT ... FROM ... LOCK IN SHARE MODE 或读取某些事务隔离级别。一致读取将忽略在读取视图中存在的记录上设置的任何锁定。

  • UPDATE ... WHERE ... 在搜索遇到的每条记录上设置一个排他的下一个键锁。

  • DELETE FROM ... WHERE ... 在搜索遇到的每条记录上设置一个排他的下一个键锁。

  • INSERT 在插入的行上设置排他锁。这个锁是索引记录锁,不是next-key锁(即没有间隙锁),并且不会阻止其他会话在插入行之前插入到间隙中。

InnoDB 有几种类型的记录级锁:

  • 记录锁:这是对索引记录的锁。

  • 间隙锁:这是在索引记录之间的间隙上的锁,或在第一条索引记录之前或最后一条索引记录之后的间隙上的锁。

  • Next-key lock:这是索引记录上的记录锁和索引记录之前的间隙上的间隙锁的组合。

看更多 :

使用 Next-Key Locking 避免幻像问题

避免死锁

于 2012-02-24T05:30:40.480 回答
1

超立方体是对的。具体来说,如果没有在条件中使用的唯一索引,它将锁定多于受影响的单行。

要查看您期望的行为,请将您的表创建更改为:

create table simple (col int unique) ENGINE=InnoDB;

col字段上的唯一索引将允许它仅锁定受影响的行。

于 2012-02-23T17:34:29.707 回答
0

“对于搜索遇到的索引记录,SELECT ... FROM ... FOR UPDATE 阻止其他会话执行 SELECT ... FROM ... LOCK IN SHARE MODE 或读取某些事务隔离级别。一致的读取将忽略任何锁在读取视图中存在的记录上设置"

哪些特定的锁可以通过 select for update 应用以使其他会话无法读取锁定的记录?

于 2014-06-16T06:24:06.190 回答