我在MySQL InnoDB引擎中发现了这种有趣的问题,任何人都可以解释为什么引擎总是声称它是一个僵局。
首先,我创建了一个包含单行,单列的表:
CREATE TABLE `SeqNum` (`current_seq_num` bigint(30) NOT NULL default '0',
PRIMARY KEY (`current_seq_num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
Query OK, 0 rows affected (0.03 sec)
mysql> insert into SeqNum values (5);
Query OK, 1 row affected (0.00 sec)
现在,我有两个MySQL连接器线程,在thread1:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select `current_seq_num` into @curr_seq FROM SeqNum FOR UPDATE;
Query OK, 1 row affected (0.00 sec)
现在,在thread2中,我完全相同:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select `current_seq_num` into @curr_seq FROM SeqNum FOR UPDATE;
在默认的innodb_lock_wait_timeout之前,thread2只是等待thread1释放它对表的独占锁,这是正常的。
但是,在thread1中,如果我输入以下更新查询:
mysql> update SeqNum set `current_seq_num` = 8;
ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction
现在,thread2完成了select查询,因为thread1退出了。
另外,在thread1中,如果我用where子句输入更新查询,它可以很好地执行:
mysql> update SeqNum set `current_seq_num` = 8 where `current_seq_num` =5
Query OK, 1 row affected (0.00 sec)
有人能解释一下吗?
答案 0 :(得分:1)
为什么你甚至想要执行这个SQL而不是
REPLACE INTO SeqNum VALUES (NULL);
SELECT last_insert_id();
答案 1 :(得分:0)
“SELECT ... FOR UPDATE”在SeqNum表上放置一个INTENTION EXCLUSIVE(IX)锁,并在符合SELECT条件的所有行上放置一个EXCLUSIVE(X)锁。
使用Innodb锁定监视器可以看到锁的状态。这可以通过创建一个特别命名的表来实现:
create table innodb_lock_monitor( i int not null ) engine = innodb;
只要发出以下命令,就会显示锁的状态:
show engine innodb status \G
当第一个线程执行“Select ... for update”时,会放置以下锁(我在表中有一行值为5):
MySQL thread id 42, query id 338 localhost root
TABLE LOCK table `test`.`SeqNum` trx id 0 1284 lock mode IX
RECORD LOCKS space id 0 page no 51 n bits 72 index `PRIMARY` of table `test`.`SeqNum` trx id 0 1284 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 8; hex 8000000000000005; asc ;; 1: len 6; hex 000000000503; asc ;; 2: len 7; hex 800000002d0110; asc - ;;
这是表上的IX锁,以及两个X锁 - 一个位于唯一行之后的间隙(supremum)上,另一个位于实际数据行上。
当在第二个线程中执行“select ... for update”时,会添加以下锁定:
TABLE LOCK table `test`.`SeqNum` trx id 0 1285 lock mode IX
RECORD LOCKS space id 0 page no 51 n bits 72 index `PRIMARY` of table `test`.`SeqNum` trx id 0 1285 lock_mode X waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 8; hex 8000000000000005; asc ;; 1: len 6; hex 000000000503; asc ;; 2: len 7; hex 800000002d0110; asc - ;;
这是表上的新IX锁,加上唯一数据行上的“X等待”锁。
原始线程可以针对整个表运行更新,也可以针对唯一的数据行运行更新,没有死锁。
这是运行“5.1.37-1ubuntu5.1”,带有REPEATABLE-READ。
请参阅: