gpt4 book ai didi

mysql - 在 MySQL 中使用 SELECT ... FOR UPDATE 死锁

转载 作者:可可西里 更新时间:2023-11-01 06:49:58 25 4
gpt4 key购买 nike

假设我有一张 table :

CREATE TABLE t (id INTEGER AUTOINCREMENT NOT NULL, desc TEXT NOT NULL)

我用 1 个元素填充表格:

INSERT INTO TABLE t VALUES (1, 'Hello')

我在 MySQL 中运行两个事务。在 t1 我运行:

START TRANSACTION;
SELECT * FROM t WHERE id = 1 FOR UPDATE;

t2 我运行:

START TRANSACTION;
SELECT * FROM t WHERE id = 1 FOR UPDATE;

此时我希望 t1 在该行上持有一个 e(X) 独占锁,而 t2 等待它获得 X 锁(并且 t2 确实被阻止了,到目前为止一切顺利)。然后我在 t1 中运行更新(没有任何 WHERE 子句!):

UPDATE t SET desc = 'Hello from t1';

t2 的这一点上,我立即得到(不需要 COMMIT 事务)错误:

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

为什么会出现此错误?我猜 t2 正在获取一个锁,需要继续进行完整的更新,造成死锁,但我不明白 t2 如何获得一个锁,因为它应该等待 t1 完成。

最佳答案

什么有效,什么无效

使两个事务都无死锁地运行的方法是更改​​ isolation level在两个连接中READ COMMITED(或READ UNCOMMITED):

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

(在开始交易之前)。

可能在 t2 中设置它就足够了,但只是为了确保示例,在两个中都设置它。

更改事务的隔离级别确实会引入一些副作用,应该告知哪些 in the manual在生产环境中更改它之前。

关于死锁的状态信息

------------------------
LATEST DETECTED DEADLOCK
------------------------
140424 8:45:46
*** (1) TRANSACTION:
TRANSACTION B6F18A3, ACTIVE 5 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 376, 1 row lock(s)
MySQL thread id 13885, OS thread handle 0x7f8b1dbd2700, query id 901012
localhost root statistics
SELECT * FROM t WHERE id = 1 FOR UPDATE
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 22921 n bits 72 index `PRIMARY` of table
`test`.`t` trx id B6F18A3 lock_mode X locks rec but not gap waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 4; hex 80000001; asc ;;
1: len 6; hex 00000b6f1883; asc o ;;
2: len 7; hex 06000059a211ea; asc Y ;;
3: len 5; hex 48656c6c6f; asc Hello;;

*** (2) TRANSACTION:
TRANSACTION B6F18A2, ACTIVE 10 sec starting index read
mysql tables in use 1, locked 1
3 lock struct(s), heap size 376, 2 row lock(s)
MySQL thread id 13888, OS thread handle 0x7f8b1f64d700, query id 901068
localhost root Updating
UPDATE t SET `descc` = 'Hello from t1'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 22921 n bits 72 index `PRIMARY` of table
`test`.`t` trx id B6F18A2 lock_mode X locks rec but not gap
Record lock, heap no 4 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 4; hex 80000001; asc ;;
1: len 6; hex 00000b6f1883; asc o ;;
2: len 7; hex 06000059a211ea; asc Y ;;
3: len 5; hex 48656c6c6f; asc Hello;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 22921 n bits 72 index `PRIMARY` of table
`test`.`t` trx id B6F18A2 lock_mode X waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 4; hex 80000001; asc ;;
1: len 6; hex 00000b6f1883; asc o ;;
2: len 7; hex 06000059a211ea; asc Y ;;
3: len 5; hex 48656c6c6f; asc Hello;;

*** WE ROLL BACK TRANSACTION (1)

说明

正如 a_horse_with_no_name 所提到的,这似乎是 MySQL 中的一个错误。事务 (2) 想要在它已经持有 X 锁的同一行上获得间隙锁。事务 (1) 等待此行上的非间隙 X 锁。我不清楚为什么这个请求会发生冲突。将隔离级别设置为 READ COMMITTED 会禁用间隙锁定。由于该示例随后有效,这暗示间隙锁定确实是这里的问题。

关于mysql - 在 MySQL 中使用 SELECT ... FOR UPDATE 死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21851119/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com