下面的测试中,创建一个含有一个字段year的表test1,并在year列上创建了一个索引,通过索引访问时,返回的结果是有序的:
$ db2 "create table test1 (year int)"
$ db2 "insert into test1 values(2010),(2007),(2005),(2012),(2000),(2017)"
$ db2 "select year from test1"
YEAR
-----------
2010
2007
2005
2012
2000
2017
6 record(s) selected.
$ db2 "create index yearidx on test1(year)"
$ db2 "runstats on table test1 and indexes all"
$ db2 "select year from test1"
YEAR
-----------
2000
2005
2007
2010
2012
2017
6 record(s) selected.
$ db2 +c "select * from test1 where year between 2007 and 2010 with RR"
YEAR
-----------
2007
2010
2 record(s) selected.
$ db2pd -db sample -locks showlock
Database Member 0 -- Database SAMPLE -- Active -- Up 0 days 01:05:41 -- Date 2017-09-15-20.37.34.581396
Locks:
Address TranHdl Lockname Type Mode Sts Owner Dur HoldCount Att ReleaseFlg rrIID TableNm SchemaNm
0x00007F219FA8AA00 3 03001B00040000000000000052 RowLock ..S G 3 1 0 0x00000010 0x00000001 1 TEST1 INST105 03001B00040000000000000052 SQLP_RECORD (obj={3;27}, rid=d(0;0;4), x0400000000000000)
0x00007F219FA8A500 3 03001B00070000000000000052 RowLock ..S G 3 1 0 0x00000010 0x00000001 1 TEST1 INST105 03001B00070000000000000052 SQLP_RECORD (obj={3;27}, rid=d(0;0;7), x0700000000000000)
0x00007F219FA8A180 3 4141414141664164FE8BC714C1 PlanLock ..S G 3 1 0 0x00000000 0x40000000 0 N/A N/A 4141414141664164FE8BC714C1 SQLP_PLAN ({41414141 64416641 14C78BFE}, loading=0)
0x00007F219FA8A980 3 03001B00050000000000000052 RowLock ..S G 3 1 0 0x00000010 0x00000001 1 TEST1 INST105 03001B00050000000000000052 SQLP_RECORD (obj={3;27}, rid=d(0;0;5), x0500000000000000)
0x00007F219FA8A300 3 01000000010000000100C034D6 VarLock ..S G 3 1 0 0x00000000 0x40000000 0 N/A N/A 01000000010000000100C034D6 SQLP_VARIATION (anchor,stmt,env,var={422,1,1,1}, loading = 0, )
0x00007F219FA7D580 3 03001B00000000000000000054 TableLock .IS G 3 1 0 0x00002000 0x00000001 0 TEST1 INST105 03001B00000000000000000054 SQLP_TABLE (obj={3;27})
$ db2 "select * from test1 where hex(rid(test1)) in ('0400000000000000','0700000000000000','0500000000000000')"
YEAR
-----------
2007
2010
2012
3 record(s) selected.
Session 1:
$ db2 +c "select * from test1 where year between 2007 and 2010 with RR"
Session 2:
$ db2 +c "delete from test1 where year=2005" => 成功
$ db2 rollback
$ db2 +c "insert into test1 values(2005)" => 成功
$ db2 rollback
$ db2 +c "insert into test1 values(2006)" => 锁超时
$ db2 rollback
$ db2 +c "delete from test1 where year=2007" => 锁超时
$ db2 rollback
$ db2 +c "delete from test1 where year=2010" => 锁超时
$ db2 rollback
$ db2 +c "insert into test1 values(2011)" => 锁超时
$ db2 rollback
$ db2 +c "delete from test1 where year=2012" => 锁超时
$ db2 rollback
$ db2 +c "insert into test1 values(2012)" => 成功
$ db2 rollback
下面以浮点数为例子,再次验证一下:
$ db2 "create table test2(num FLOAT)"
$ db2 "insert into test2 values(3.1415926),(2.71828),(9.8),(5.55),(6.66)"
$ db2 "create index numidx on test2(num)"
$ db2 "runstats on table test2 and indexes all"
$ db2 "select * from test2"
NUM
------------------------
+2.71828000000000E+000
+3.14159260000000E+000
+5.55000000000000E+000
+6.66000000000000E+000
+9.80000000000000E+000
5 record(s) selected.
Session1:
inst105@db2a:~$ db2 +c "select * from test2 where num=6.66 with RR"
NUM
------------------------
+6.66000000000000E+000
1 record(s) selected.
在另一个session里,测试结果表明,加锁范围确实是(5.55,9.8]
Session2:
$ db2 +c "delete from test2 where num=5.55" =>成功
$ db2 rollback
$ db2 +c "insert into test2 values(5.56)" => 锁超时
$ db2 rollback
$ db2 +c "delete from test2 where num=9.8" => 锁超时
$ db2 rollback
$ db2 +c "insert into test2 values(9.8)" =>成功
$ db2 rollback
1.
Next key lock 可以这么理解:要想在A记录之后插入一条数据,那么必须要先获得第A+1条记录的锁。第一个例子中,要在2007到2010之间插入数据,必须先获得2010的锁;要在2010和2012之间插入数据(比如2010),必须先获得2012的锁;要在2005到2007之间插入数据(比如2007),必须先获得2007的锁。这里不必过于关注边界是开区间还是闭区间,最重要的是中间这个gap, MySQL中也有类似的概念和相似的效果。
2. 在第2个例子中,如果索引numidx改为唯一索引,那么session 1里的select语句只会在6.66上加一个行锁,而不在9.8上加锁,实际上的锁定范围是(5.55,6.66],插入6.00会报错超时,插入7.00不会,但MySQL这种情况下不需要Gap lock,插入6.00也可以成功。也就是说,在RR隔离级别和唯一索引的情况下,如果第N条记录上有锁,那么db2不允许插入N-1~N之间的记录,但MySQL允许。
参考资料:
http://hedengcheng.com/?p=771