时间:2021-07-01 10:21:17 帮助过:26人阅读
```` session 1: start transaction ; select * from news where number=4 for update ; session 2: start transaction ; insert into news value(2,4);#(阻塞) insert into news value(2,2);#(阻塞) insert into news value(4,4);#(阻塞) insert into news value(4,5);#(阻塞) insert into news value(7,5);#(执行成功) insert into news value(9,5);#(执行成功) insert into news value(11,5);#(执行成功) ````
检索条件number=4,向左取得最靠近的值2作为左区间,向右取得最靠近的5作为右区间,因此,session 1的间隙锁的范围(2,4),(4,5),如下图所示:
间隙锁锁定的区间为(2,4),(4,5),即记录(id=1,number=2)和记录(id=3,number=4)之间间隙会被锁定,记录(id=3,number=4)和记录(id=6,number=5)之间间隙被锁定。
因此记录(id=2,number=4),(id=2,number=2),(id=4,number=4),(id=4,number=5)正好处在(id=3,number=4)和(id=6,number=5)之间,所以插入不了,需要等待锁的释放,而记录(id=7,number=5),(id=9,number=5),(id=11,number=5)不在上述锁定的范围内,因此都会插入成功。
案例二:
```` session 1: start transaction ; select * from news where number=13 for update ; session 2: start transaction ; insert into news value(11,5);#(执行成功) insert into news value(12,11);#(执行成功) insert into news value(14,11);#(阻塞) insert into news value(15,12);#(阻塞) update news set id=14 where number=11;#(阻塞) update news set id=11 where number=11;#(执行成功) ````
检索条件number=13,向左取得最靠近的值11作为左区间,向右由于没有记录因此取得无穷大作为右区间,因此,session 1的间隙锁的范围(11,无穷大),如下图所示:
此表中没有number=13的记录的,innodb依然会为该记录左右两侧加间隙锁,间隙锁的范围(11,无穷大)。
有人会问,为啥update news set id=14 where number=11会阻塞,但是update news set id=11 where number=11却执行成功呢?
间隙锁采用在指定记录的前面和后面以及中间的间隙上加间隙锁的方式避免数据被插入,此图间隙锁锁定的区域是(11,无穷大),也就是记录(id=13,number=11)之后不能再插入记录,update news set id=14 where number=11这条语句如果执行的话,将会被插入到(id=13,number=11)的后面,也就是在区间(11,无穷大)之间,由于该区间被间隙锁锁定,所以只能阻塞等待,而update news set id=11 where number=11执行后是会被插入到(id=13,number=11)的记录前面,也就不在(11,无穷大)的范围内,所以无需等待,执行成功。
案例三:
```` session 1: start transaction ; select * from news where number=5 for update; session 2: start transaction ; insert into news value(4,4);#(阻塞) insert into news value(4,5);#(阻塞) insert into news value(5,5);#(阻塞) insert into news value(7,11);#(阻塞) insert into news value(9,12);#(执行成功) insert into news value(12,11);#(阻塞) update news set number=5 where id=1;#(阻塞) update news set id=11 where number=11;#(阻塞) update news set id=2 where number=4 ;#(执行成功) update news set id=4 where number=4 ;#(阻塞) ````
检索条件number=5,向左取得最靠近的值4作为左区间,向右取得11为右区间,因此,session 1的间隙锁的范围(4,5),(5,11),如下图所示:
有人会问,为啥insert into news value(9,12)会执行成功?间隙锁采用在指定记录的前面和后面以及中间的间隙上加间隙锁的方式避免数据被插入,(id=9,number=12)很明显在记录(13,11)的后面,因此不再锁定的间隙范围内。
为啥update news set number=5 where id=1会阻塞?
number=5的记录的前面,后面包括中间都被封锁了,你这个update news set number=5 where id=1根本没法执行,因为innodb已经把你可以存放的位置都锁定了,因为只能等待。
同理,update news set id=11 where number=11由于记录(id=10,number=5)与记录(id=13,number=11)中间的间隙被封锁了,你这句sql也没法执行,必须等待,因为存放的位置被封锁了。
案例四:
session 1: start transaction; select * from news where number>4 for update; session 2: start transaction; update news set id=2 where number=4 ;#(执行成功) update news set id=4 where number=4 ;#(阻塞) update news set id=5 where number=5 ;#(阻塞) insert into news value(2,3);#(执行成功) insert into news value(null,13);#(阻塞)
检索条件number>4,向左取得最靠近的值4作为左区间,向右取无穷大,因此,session 1的间隙锁的范围(4,无穷大),如下图所示:
session2中之所以有些阻塞,有些执行成功,其实就是因为插入的区域被锁定,从而阻塞。
next-key锁
next-key锁其实包含了记录锁和间隙锁,即锁定一个范围,并且锁定记录本身,InnoDB默认加锁方式是next-key 锁。
上面的案例一session 1中的sql是:select * from news where number=4 for update ;
next-key锁锁定的范围为间隙锁+记录锁,即区间(2,4),(4,5)加间隙锁,同时number=4的记录加记录锁。
https://www.cnblogs.com/crazylqy/p/7821481.html
Mysql加锁过程详解(9)-innodb下的记录锁,间隙锁,next-key锁
标签:多版本 bsp ima val 中间 修改 基本知识 value 锁定