restarting transaction
mysql> insert into test values (26);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values (21);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into test values (16);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into test values (6);
Query OK, 1 row affected (0.01 sec)
从这里可以看出,现在被锁住的区间就只有[16,21)了。
有了前面对三种类型的加锁解释,现在可以来解释为什么会这样了,在innodb表中 delete from where ..针对扫描到的索引记录加next-key锁(具体的什么语句加什么锁可以查看手册,另外需要说明一下,行锁加锁对象永远是索引记录,因为innodb中表即索引) 。
在(一)中,实际上加的next-key lock就是(11,11] 因此也只有a=11这一条记录被锁住,其他所有插入都没有关系。
在(二)中,因为a=22这条记录不存在,而且22比表里所有的记录值都大,所以在innodb看来锁住的区间就是(14, 无穷大)。所以在插入14以后的值都提示被锁住,而14之前的则可以。
在(三)种,a=21也是不存在,但是在表里面21前后都有记录,因此这里next-key lock的区间也就是(15,21],因此不在这个区间内的都可以插入。
那么为什么next-key lock都是下界开区间,上界闭区间呢?这个倒不重要,管它呢,但是有一点我个人却觉得比较怪,比如说
delete test where a > 11 #------- 1
它的next-key lock是(11, 无穷大)
delete test where a < 11 #------- 2
它的next-key lock是(无穷小, 10]
这样给人的感觉就很怪,因为在手册上对next-key lock的定义:
Next-key lock: This is a combination of a record lock on the index record and a gap lock on the gapbefore the index record.
而在1那种情况下,如果按照手册上的解释,记录锁和它之前的gap那么就会有些牵强。[今天再次看了一遍官方手册,是之前自己的理解不到位,这个before是对的,因为innodb在加锁时是所有扫描过程中遇到的记录都会被加锁,那么对于1那种情况,实际上是从12开始扫描,但是因为要保证a>11的都被delete掉,因此得一直扫描下去那自然最大值就是无穷大,因为这个next-key lock就是无穷大这条记录(这是假设的一条记录,表示一个边界)加上它之前的gap lock (11, 无穷大),所以在任何时候next-lock都是record lock加上这个record之前的一个gap lock]
但是只要我们自己能理解就行了:记录锁---锁单条记录;区间锁---锁一个开区间;next-key 锁---前面两者的结合,而不要管什么before。
另外next-key lock虽然在很多时候是锁一个区间,但要明白一个区间也可能只有一个元素,因此在称delete from tb where key=x 这种情况下加next-key锁也是完全正确的。
另外还提两点:
1.如果我们的SQL语句里面没有利用到索引,那么加锁对象将是所有行(但不是加表锁),所以建索引是很重要的
2.next-key lock是为防止幻读的发生,而只有repeatable-read以及以上隔离级别才能防止幻读,所以在read-committed隔离级别下面没有next-key lock这一说法。
|