赞
踩
//对读取的记录加共享锁(S型锁) select ... lock in share mode; //对读取的记录加独占锁(X型锁) select ... for update;
当事务提交了,锁就会被释放
//对操作的记录加独占锁(X型锁) update table .... where id = 1; //对操作的记录加独占锁(X型锁) delete from table where id = 1;
共享锁(S锁)满足读读共享,读写互斥。独占锁(X锁)满足写写互斥、读写互斥。 【指行(记录)锁】间隙锁之间是兼容的(因为目的是为了防止幻读)
在读已提交隔离RC级别下,行级锁的种类只有记录锁,也就是仅仅把一条记录锁上。
在可重复读隔离RR级别下,行级锁的种类除了有记录锁,还有间隙锁(目的是为了避免幻读),所以行级锁的种类主要有三类:
Record Lock,记录锁,也就是仅仅把一条记录锁上;
Gap Lock,间隙锁,锁定一个范围,但是不包含记录本身;
Next-Key Lock:Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。
加锁的对象是索引,加锁的基本单位是 next-key lock,它是由记录锁和间隙锁组合而成的,next-key lock 是前开后闭区间,而间隙锁是前开后开区间。【锁是加在索引上的】
在能使用记录锁或者间隙锁就能避免幻读现象的场景下, next-key lock 就会退化成记录锁或间隙锁
select * from performance_schema.data_locks\G;
查看事务执行 SQL 过程中加了什么锁。
LOCK_TYPE 中的 RECORD 表示行级锁,而不是记录锁的意思。
通过 LOCK_MODE 可以确认是 next-key 锁,还是间隙锁,还是记录锁:
如果 LOCK_MODE 为 X
,说明是 next-key 锁;
如果 LOCK_MODE 为 X, REC_NOT_GAP
,说明是记录锁;
如果 LOCK_MODE 为 X, GAP
,说明是间隙锁;
LOCK_DATA 就表示锁的范围「右边界」
总的思路就是,尽可能避免幻读的发生(不让其他记录的插入),对于等值查询(>=)查到的加临建锁或者记录锁(看是范围查询 [大于情况才记录锁] 还是等值查询),因为这个记录等值记录也要上锁。对于非等值的查到了,只是加间隙锁,因为是开区间的。
注意:结合临建锁(包含记录锁)是左开右闭(在>=时是记录锁锁住左边界)。 间隙锁是开区间。
注意:
对于不唯一的不加记录锁的原因【因为不具有唯一性,所以如果只加记录锁(记录锁无法防止插入,只能防止删除或者修改)】
因为【插入时不会阻塞,报主键冲突错误,删除和更新则会阻塞】
在线上在执行 update、delete、select ... for update 等具有加锁性质的语句,一定要检查语句是否走了索引,如果是全表扫描的话,会对每一个索引加 next-key 锁,相当于把整个表锁住了,这是挺严重的问题。
索引上的等值查询(唯一索引时),给不存在的记录加锁时,优化为间隙锁
此处「唯一索引」是用「主键索引」作为案例说明的
加锁的对象是针对索引,因为这里查询语句扫描的 B+ 树是聚簇索引树,即主键索引树,所以是对主键索引加锁。将对应记录的主键索引加 记录锁后,就意味着其他事务无法对该记录进行更新和删除操作了。
用唯一索引进行等值查询的时候,查询的记录存不存在,加锁的规则也会不同:
当查询的记录是「存在」的,在索引树上定位到这一条记录后,将该记录的索引中的 next-key lock 会退化成「记录锁」。【因为仅靠记录锁也能避免幻读的问题。】
当查询的记录是「不存在」的,在索引树找到第一条大于该查询记录的记录后,将该记录的索引中的 next-key lock 会退化成「间隙锁」【需要锁住这个不存在的id防止被别人插入了,不需要锁住比他的大的这一条数据】开区间(因为第一条大于的是已经存在的,所以会报主键冲突的错,不需要加) 【退化原因:对于大于所查的id,并不需要保证他的幻读问题,只要保证所查询的id不要出现幻读问题就可以】
二级索引:都会对查到的记录的主键索引项加上记录锁,还会对二级索引加行级锁(唯一索引的话,退化规则和主键索引一样)
不存在的锁边界:LOCK_DATA 就表示锁的范围「右边界」(此处为5),锁范围的「左边界」是表中 id 为 5 的上一条记录的 id 值,即 1。
索引上的范围查询(唯一索引)--会访问到不满足条件的第一个值为止
临建锁都是两个已有的记录之间的锁 (a,b] 。
当唯一索引进行范围查询时,会对每一个扫描到的索引加 next-key 锁,然后如果遇到下面这些情况,会退化成记录锁或者间隙锁:
情况一:针对「大于等于」的范围查询,因为存在等值查询的条件,那么如果等值查询的记录是存在于表中,那么该记录的索引中的 next-key 锁会退化成记录锁。【其他的大于呢???就不会退化为间隙锁了,直接next-key-lock】------【 Innodb 存储引擎中,会用一个特殊的记录来标识最后一条记录,该特殊的记录的名字叫 supremum pseudo-record ,所以后面的next-key是(,+oo]】----【等于时的等值条件为什么只有她是记录锁,因为临建锁是左开右闭,会导致左边界的等值查询无法锁住,所以就用记录锁】
情况二:针对「小于或者小于等于」的范围查询,要看条件值的记录是否存在于表中:
当条件值的记录在表中(存在),如果是「小于」条件的范围查询,扫描到终止范围查询的记录时,该记录的索引的 next-key 锁会退化成间隙锁,其他扫描到的记录,都是在这些记录的索引上加 next-key 锁;如果「小于等于」条件的范围查询,扫描到终止范围查询的记录时,该记录的索引 next-key 锁不会退化成间隙锁。其他扫描到的记录,都是在这些记录的索引上加 next-key 锁。【把要查的都锁住,其他的不影响,所以要临建锁】-----【此处等值的加记录锁大可不必,因为又不止锁这个记录, 大于情况是因为临建锁左开右闭】
当条件值的记录不在表(不存在)中,那么不管是「小于」还是「小于等于」条件的范围查询,扫描到终止范围查询的记录时,该记录的索引的 next-key 锁会退化成间隙锁,其他扫描到的记录,都是在这些记录的索引上加 next-key 锁。【因为不存在这个终止条件,不需要锁住她】
索引上的等值查询(普通索引),向右遍历时最后一个【因为可能不唯一】值不满足查询需求时,next-key lock 退化为间隙锁。
查询记录的存不存在:区别在于会不会对主键索引添加记录锁(他是唯一性的)
因为存在两个索引,一个是主键索引,一个是非唯一索引(二级索引),所以在加锁时,同时会对这两个索引都加锁,但是对主键索引加锁的时候,只有满足查询条件的记录才会对它们的主键索引加锁。
当查询的记录「存在」时,由于不是唯一索引,所以肯定存在索引值相同的记录,于是非唯一索引等值查询的过程是一个扫描的过程,直到扫描到第一个不符合条件的二级索引记录就停止扫描,然后在扫描的过程中,对扫描到的二级索引记录加的是 next-key 锁,而对于第一个不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁【因为不具有唯一性,所以如果只加记录锁(记录锁无法防止插入,只能防止删除或者修改)】。同时,在符合查询条件的记录的主键索引上加记录锁。【因为只有一条记录,唯一性】
当查询的记录「不存在」时,扫描到第一条不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁。因为不存在满足查询条件的记录,所以不会对主键索引加锁。【因为她不存在呀】
非唯一索引范围查询,索引的 next-key lock 不会有退化为间隙锁和记录锁的情况,也就是非唯一索引进行范围查询时,对二级索引记录加锁都是加 next-key 锁。
对于有加索引的,是查询记录的时候,是通过索引扫描的方式查询的,然后对扫描出来的记录进行加锁。
对于没有加索引的在查询的时候就会对每一条记录的索引上都会加 next-key 锁,这样就相当于锁住的全表,这时如果其他事务对该表进行增、删、改操作的时候,都会被阻塞。
update 和 delete 语句如果查询条件不加索引,那么由于扫描的方式是全表扫描。【不只是select、语句】
唯一索引等值查询:
当查询的记录是「存在」的,在索引树上定位到这一条记录后,将该记录的索引中的 next-key lock 会退化成「记录锁」。
当查询的记录是「不存在」的,在索引树找到第一条大于该查询记录的记录后,将该记录的索引中的 next-key lock 会退化成「间隙锁」。
非唯一索引等值查询:
当查询的记录「存在」时,由于不是唯一索引,所以肯定存在索引值相同的记录,于是非唯一索引等值查询的过程是一个扫描的过程,直到扫描到第一个不符合条件的二级索引记录就停止扫描,然后在扫描的过程中,对扫描到的二级索引记录加的是 next-key 锁,而对于第一个不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁。同时,在符合查询条件的记录的主键索引上加记录锁。
当查询的记录「不存在」时,扫描到第一条不符合条件的二级索引记录,该二级索引的 next-key 锁会退化成间隙锁。因为不存在满足查询条件的记录,所以不会对主键索引加锁。
非唯一索引和主键索引的范围查询的加锁规则不同之处在于:
唯一索引在满足一些条件的时候,索引的 next-key lock 退化为间隙锁或者记录锁。
非唯一索引范围查询,索引的 next-key lock 不会退化为间隙锁和记录锁。
唯一索引:
非唯一索引(二级索引)
对于二级索引中唯一索引规格和主键索引一样!(会用到记录锁,因为唯一)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。