最近系统碰到一个死锁问题,虽然问题解决了,但是对innodb的锁还有一些疑问,想请教高人。
mysql reference上有一个死锁的简单例子:
有一张表t,CREATE TABLE t (i INT) ENGINE = InnoDB;
插入数据,INSERT INTO t (i) VALUES(1);
客户端A:
START TRANSACTION;
SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE; ----①
然后客户端B,START TRANSACTION;DELETE FROM t WHERE i = 1;-------②这时候阻塞,
然后再客户端A:DELETE FROM t WHERE i = 1;-----③这时候就会产生死锁,通过命令show innodb status查看,在上面执行第①条语句的时候,在t上有一个IS锁和这条记录上有个S锁,在第②条语句的时候第二个事务拥有对t的IX锁,等待X锁。我的问题是:1.死锁产生的原因是不是由于第二个事务拥有了IX锁,而不能得到X锁(由于第一个事务的S锁),而第一个事务也是要取得X锁,但由于第二个事务拥有了IX锁(IX和X冲突),所以产生死锁?2.在执行第②条语句的时候,为什么能个获得IX锁?因为我从手册上看S锁和IX锁是有冲突的,既然第一个事务已经取得了S锁,那么第二个事务为什么还能取得IX锁?
还望各位不吝赐教。
jiwang1980 发表于 2011-12-19 09:48
e,,第二个事务需要的两个锁都没有获取到,(IX和X),这两个锁都在等
但是我开启innodb_lock_monitor以后,看到第二个事务以及取得了IX锁,等待X锁。
ABLE LOCK table `test`.`t` trx id 101411 lock mode IX
RECORD LOCKS space id 0 page no 29448 n bits 72 index `GEN_CLUST_INDEX` of table `test`.`t` trx id 101411 lock_mode X waiting
客户端A:
START TRANSACTION;
SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE; ----①
然后客户端B,START TRANSACTION;DELETE FROM t WHERE i = 1;-------②这时候阻塞,
然后再客户端A:DELETE FROM t WHERE i = 1;
客户端A:LOCK IN SHARE MODE 会加上 S锁,也即允许其他线程读,但是不能修改,也即可以再加S锁,但是不能修改
客户端B:DELETE FROM t WHERE i = 1; 将等待记录的写锁
客户端A:DELETE FROM t WHERE i = 1;将会成功获得写锁权利,因为该事务已经获得记录的S锁,所以事务内部升级锁是没问题的
客户端B:发现想加写锁的记录被删除了,那么也是属于死锁的一种无法成功加锁.
上述要注意事务的隔离级别,否则不同也是效果不一样的,测试是在RR模式下才可重现.