来自文档:
如果发生重复键错误,则在重复索引上共享锁 记录已设置。共享锁的这种使用可能会导致僵局 如果另一个会话尝试插入同一行 会话已经有一个独家锁。如果另一个 会话删除行。
与文档中的示例一起进行
假设InnoDB表T1具有以下结构:
CREATE TABLE t1 (i INT, PRIMARY KEY (i)) ENGINE = InnoDB;
现在假设三个会话按顺序执行以下操作:
会话1:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
会议2:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
会议3:
START TRANSACTION;
INSERT INTO t1 VALUES(1);
会话1:
ROLLBACK;
第一次按会话1通过 排。会议2和3的操作都导致重复键 错误,他们都要求该行共享锁。会议1时 向后回滚,它在该行上释放其独家锁定,排队 批准了第2和3会议的共享锁请求。在此刻, 会议2和3僵局:都无法获得独家锁 由于对方的共享锁,该行。
我有一些问题:
1)插入查询在其正在插入的行上采用独家锁定。因此,假设T1在第1行上插入,它将锁定第1行1。现在,当T2撰写时,将InnoDB在执行之前评估查询,并确定它将编写相同的PK(与i = 1的行)并等待T2?或者它将开始执行T2并发现它给出重复的密钥错误或违反PK。
2)为什么T2和T3拿共享锁?在插入过程中,共享锁如何出现?
1)插入查询在该行上采用独家锁 插入。因此,假设T1在第1行上插入,它将锁定第1行。 现在,当T2写作时,Will InnoDB在此之前评估查询 执行它并发现它将编写相同的PK(行 使用i = 1)并进行T2等待?或者它将开始执行T2和 发现它给出重复的密钥错误或违反PK。
我认为您正在简化术语/过程。解析查询和执行之前,它需要获取必要的锁。正是在这一点上确定:
- 会话1获得独家锁,因为它正在插入,没有其他锁
- 会议2和第3节因共享锁定为排队,因为独家锁定已按照会议1进行,并且会议2和3在重复的密钥错误 中
2)为什么T2和T3拿共享锁?共享锁如何来 在插入时进入图片?
每上文,第2和3会议会为共享锁排队,因为它们处于重复的密钥错误中。但是,当Session 1删除密钥并发布独家锁定时,现在会议2和3都将获得共享锁。在这一点上,两者都试图获取一个独家锁以完成插件。但是,没有一个人都不能,因为另一个已经持有共享锁。因此,没有授予独家锁,他们僵持。
-
对于会话2和3:InnoDB在执行前评估查询并确定该行是否已锁定(i = 1的行),交易将等待解锁隐含的行。
。当您在第一个会话中插入后执行
SHOW ENGINE INNODB STATUS
,然后在课程2和3中运行插入后:------------ TRANSACTIONS ------------ Trx id counter 2079155 Purge done for trx's n:o < 2079150 undo n:o < 0 state: running but idle History list length 594 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 2079154, ACTIVE 21 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s) MySQL thread id 540, OS thread handle 0x7ff989386700, query id 1683 localhost root update INSERT INTO t1 VALUES(1) ------- TRX HAS BEEN WAITING 21 SEC FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 4190 page no 3 n bits 72 index `PRIMARY` of table `temp`.`t1` trx id 2079154 lock mode S locks rec but not gap waiting Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 80000001; asc ;; 1: len 6; hex 0000001fb9af; asc ;; 2: len 7; hex 9c000001d30110; asc ;; ------------------ ---TRANSACTION 2079153, ACTIVE 43 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s) MySQL thread id 541, OS thread handle 0x7ff989355700, query id 1680 localhost root update INSERT INTO t1 VALUES(1) ------- TRX HAS BEEN WAITING 43 SEC FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 4190 page no 3 n bits 72 index `PRIMARY` of table `temp`.`t1` trx id 2079153 lock mode S locks rec but not gap waiting Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0 0: len 4; hex 80000001; asc ;; 1: len 6; hex 0000001fb9af; asc ;; 2: len 7; hex 9c000001d30110; asc ;;
解锁行后(会话1的回滚)会话2将获得错误:
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
,会话3:Query OK, 1 row affected
-
课程2和3没有共享锁,他们在队列中获得一个,因为第一个会话的锁定是独有的,需要等待。在这种情况下,会议3将获得一个并插入记录。
共享锁:一种锁定的锁,允许其他交易读取锁定对象,并在其上获取其他共享锁,但是 不写它。
的对立面。独家锁定:一种锁定,可防止其他任何交易锁定同一行。取决于交易隔离 级别,这种锁可能会阻止其他交易写作 到同一行,或者也可能阻止其他交易无法阅读 同一行。默认的InnoDB隔离级别,可重复的读取, 通过允许交易读取行的行,可以使更高的并发 拥有独家锁,一种称为一致读取的技术。
问题2:
2)为什么T2和T3拿共享锁?在插入过程中如何出现共享锁?
它需要在现有条目上锁定,以便随后的尝试插入重复记录的尝试始终如一地失败。