我正在阅读有关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
,行为也是相同的。任何人都可以描述这个例子背后的锁定背景(锁定的地点和原因)?
答案 0 :(得分:9)
InnoDB设置特定类型的锁,如下所示。
SELECT ... FROM是一致读取,读取数据库的快照并设置无锁定,除非事务隔离级别设置为SERIALIZABLE。对于SERIALIZABLE级别,搜索会在遇到的索引记录上设置共享的下一键锁定。
SELECT ... FROM ... LOCK IN SHARE MODE在搜索遇到的所有索引记录上设置共享的下一键锁定。
对于搜索遇到的索引记录,SELECT ... FROM ... FOR UPDATE阻止其他会话进行SELECT ... FROM ... LOCK IN SHARE MODE或从某些事务隔离级别读取。一致性读取将忽略在读取视图中存在的记录上设置的任何锁定。
UPDATE ... WHERE ...在搜索遇到的每条记录上设置一个独占的下一键锁定。
DELETE FROM ... WHERE ...在搜索遇到的每条记录上设置一个独占的下一键锁定。
INSERT在插入的行上设置独占锁。此锁是索引记录锁,而不是下一键锁(即没有间隙锁),并且不会阻止其他会话在插入行之前插入间隙。
InnoDB有几种类型的记录级锁:
记录锁定:这是对索引记录的锁定。
差距锁定:这是锁定索引记录之间的间隙,或锁定在第一个或最后一个索引记录之前的间隙。
下一键锁定:这是索引记录上的记录锁定和索引记录之前的间隙上的间隙锁定的组合。
查看更多:
答案 1 :(得分:1)
ypercube没错。具体来说,如果没有在条件中使用的唯一索引,它将锁定比受影响的单行更多的内容。
要查看您期望的行为,请将表格创建更改为:
create table simple (col int unique) ENGINE=InnoDB;
col
字段上的唯一索引将允许它仅锁定受影响的行。
答案 2 :(得分:0)
“对于搜索遇到的索引记录,SELECT ... FROM ... FOR UPDATE阻止其他会话执行SELECT ... FROM ... LOCK IN SHARE MODE或从某些事务隔离级别读取。一致读取将忽略在读取视图“
中存在的记录上设置的任何锁定可以通过select更新应用哪些锁定,以便其他会话无法读取锁定记录?