Pri*_*oel 5 mysql transaction locking
从文档:
如果发生重复键错误,则在重复索引记录上设置共享锁。如果另一个会话已经拥有排它锁,那么如果有多个会话尝试插入同一行,则使用共享锁可能会导致死锁。如果另一个会话删除该行,就会发生这种情况。
使用文档中的示例,
假设 InnoDB 表 t1 具有以下结构:
CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB;
Run Code Online (Sandbox Code Playgroud)
现在假设三个会话依次执行以下操作:
第 1 节:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
Run Code Online (Sandbox Code Playgroud)
第 2 节:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
Run Code Online (Sandbox Code Playgroud)
第 3 节:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
Run Code Online (Sandbox Code Playgroud)
第 1 节:
ROLLBACK;
Run Code Online (Sandbox Code Playgroud)
会话 1 的第一个操作获取该行的排它锁。会话 2 和 3 的操作都会导致重复键错误,并且它们都为该行请求共享锁。当会话 1 回滚时,它会释放它对该行的排它锁,并且会话 2 和 3 的排队共享锁请求被授予。此时,会话 2 和 3 死锁:由于对方持有共享锁,因此都无法获取该行的排他锁。
我有一些问题 :
1) 插入查询对其插入的行进行排他锁。因此,假设 T1 在第 1 行插入,它将锁定第 1 行。现在当 T2 写入时,INNODB 会在执行之前评估查询并发现它将写入相同的 PK(i = 1 的行)让T2等待?或者它会开始执行T2并发现它给出了重复的密钥错误或PK违规。
2)为什么T2和T3采用共享锁?在插入过程中共享锁是如何出现的?
我在一个简单的 bash 脚本中对这种情况做了一个小模拟:
\n\n\xe2\x9e\x9c rsandbox_5_6_30 cat test.sh \n./m -e "START TRANSACTION; INSERT INTO test1 VALUES(6); select sleep(3); rollback;" test 2> tx1 &\n./m -e "START TRANSACTION; INSERT INTO test1 VALUES(6); select sleep(5); commit;" test 2> tx2 &\n./m -e "START TRANSACTION; INSERT INTO test1 VALUES(6); select sleep(5); commit;" test 2> tx3 &\n\n./m -e "SHOW ENGINE INNODB STATUS\\G" test > istatus\nRun Code Online (Sandbox Code Playgroud)\n\n结果:
\n\n\xe2\x9e\x9c rsandbox_5_6_30 cat tx1 \nERROR 1062 (23000) at line 1: Duplicate entry \'6\' for key \'PRIMARY\'\n\xe2\x9e\x9c rsandbox_5_6_30 cat tx2\nERROR 1062 (23000) at line 1: Duplicate entry \'6\' for key \'PRIMARY\'\n\xe2\x9e\x9c rsandbox_5_6_30 cat tx3\nRun Code Online (Sandbox Code Playgroud)\n\n交易状态:
\n\n---TRANSACTION 265035, not started\nMySQL thread id 4, OS thread handle 0x700000b0b000, query id 204 localhost msandbox cleaning up\n---TRANSACTION 265017, not started\nMySQL thread id 3, OS thread handle 0x700000ac7000, query id 171 localhost msandbox cleaning up\n---TRANSACTION 265041, ACTIVE 0 sec\n1 lock struct(s), heap size 360, 0 row lock(s), undo log entries 1\nMySQL thread id 31, OS thread handle 0x700000ca3000, query id 210 localhost msandbox User sleep\nselect sleep(5)\nRun Code Online (Sandbox Code Playgroud)\n\n如果您在一定延迟内执行第一个事务,则可能会出现一个帧,其中一个后续事务被死锁检测杀死,从而使另一个事务插入该值。
\n\n活动事务的状态反映仍然需要显式提交(撤消日志条目 1)。
\n\n——编辑第二次
\n\n“由于对方持有共享锁,双方都无法获取该行的独占锁。” 实际上,死锁只会杀死 1 个事务,而不是同时杀死两个事务。所以EL是在第二次时获得的。
\n\n由于间隙锁定的工作原理,我们看到了执行之间的差异。当检测到重复键错误时,第三个事务试图获取共享锁,从而发生死锁。发生这种情况时,第二个事务会获取共享锁,从而产生死锁并终止第三个事务。这是对同一记录的并发写入量的限制。
\n| 归档时间: |
|
| 查看次数: |
965 次 |
| 最近记录: |