【问题标题】:inno db isolation levels and lockinginnodb 隔离级别和锁定
【发布时间】:2012-02-19 22:44:45
【问题描述】:

我正在阅读有关 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,行为也是相同的。谁能描述一下这个例子背后的锁定背景(锁定的位置和原因)?

【问题讨论】:

  • 了解 REPEATABLE READ 在:Transaction levels:For locking reads (SELECT with FOR UPDATE or LOCK IN SHARE MODE), UPDATE, and DELETE statements, locking **depends on whether the statement uses a unique index with a unique search condition**, or a range-type search condition. ...

标签: mysql transactions innodb isolation-level database-locking


【解决方案1】:

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 ... 在搜索遇到的每条记录上设置一个排他的 next-key 锁。

  • DELETE FROM ... WHERE ... 为搜索遇到的每条记录设置一个排他的 next-key 锁定。

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

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

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

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

  • 下一个键锁:这是索引记录上的记录锁和索引记录之前的间隙上的间隙锁的组合。

查看更多:

Avoiding the Phantom Problem Using Next-Key Locking

Avoiding deadlock

【讨论】:

  • 很好的概述,但我想知道索引如何适合您编写的内容。为什么索引的存在会改变我的示例中的行为?
  • 下一个键锁定结合了索引行锁定和间隙锁定。 InnoDB 执行行级锁定的方式是,当它搜索或扫描表索引时,它会在它遇到的索引记录上设置共享或排他锁。此外,索引记录上的 next-key 锁定也会影响该索引记录之前的“间隙”。也就是说,next-key 锁是索引记录锁加上索引记录前面的间隙上的间隙锁。
【解决方案2】:

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

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

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

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

【讨论】:

  • 我发现,需要有一个索引,但它不需要是唯一的。
  • 啊,当我读到它uses a unique index with a unique search condition 时,我把它当作unique 索引,但它们一定意味着唯一的,具体的。
  • ypercube 写的内容并不(完全)相关。如果存在唯一索引和唯一搜索条件,则使用记录锁而不是next-key锁。在我的示例中,是否使用记录锁或下一个键锁并不重要,因为第一次更新可能锁定的唯一间隙是在 1 之前,第二次更新引用 2。重要的是存在 an(y ) 索引,因为更新不只锁定目标记录,它锁定它在搜索目标记录期间遇到的所有记录。无索引 => 全扫描 => 锁定所有记录。
  • 我会说它是相关的,只是没有那么准确。它粗略地描绘了您详细描述的内容。感谢您的更新!
【解决方案3】:

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

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

【讨论】:

  • 对不起,这不是答案。考虑发布一个单独的问题。
  • stalkoverflow 人们不允许我将其作为新问题发布
  • mysql中没有这样的锁,解决方法见this answer
猜你喜欢
  • 2013-12-09
  • 2015-08-04
  • 2018-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-18
  • 2014-03-23
  • 1970-01-01
相关资源
最近更新 更多