在MySQL中使用SELECT ... FOR UPDATE的死锁

时间:2014-02-18 10:37:20

标签: mysql

假设我有桌子:

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正在获取完整的UPDATE需要继续进行,造成死锁,但我不明白t2如何获得锁定,因为它应该等待{ {1}}完成。

1 个答案:

答案 0 :(得分:2)

什么有效,什么无效

使两个事务都运行而没有死锁的方法是在两个连接中将isolation level更改为 READ COMMITED (或 READ UNCOMMITED ): / p>

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

start transaction之前)。

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)持有并等待相同的锁定,这没有任何意义。