本文还未整理完成,目前主要整理的是mysql中锁的种类,以及基本的使用方式。
一致性读
事务利用MVCC进行操作称为一致性读(Consistent Rcad)。或者一致性无锁读(有的资料也称之为快照读)。所有普通的SELECT语句在READ COMMITED、
REPEARABLE READ隔离级别下都算是一致性读,一致性读并不会对表中 的任何记录进行加锁操作 其他事务可以自由地对表中的记录进行改动。
共享锁和独占锁
- 共享锁(Shared Lock)简称S锁.在事务要读取一条记录时 需要先获取该记录的锁
- 独占锁(Exclusive Lock)也常称为排他锁,简称X锁。在事务要改动一条记录时需要先获取该记录 锁。
锁的兼容情况
锁定读的语句
读取记录添加S锁
1 | select ... LOCK IN SHARE MODE |
读取添加X锁
1 | SELECT ... FRO UPDATE |
意向锁
意向锁,主要用来判断当前表是否被加锁,不会对修改读取有任何阻塞操作。
主要有俩种
- 意向共享锁( Intention Shared Lock )简称IS,当事务准备在某条记录上加锁时
需要先在表级别加IS锁 - 意向独占锁(Intention Exclusive Lock) 简称IX锁,当事务准备在某条记录上加
时,需要先在表级别一个IX锁。
他们俩都是表级锁,它们的提出仅仅为了在之后加表级别的S锁和X锁时可以快速判断表中的记录是否被上锁,以避免用遍历的方式来查看表中有没有上锁的记录:也就是说其实IS锁和IX锁是兼容的IX锁和IX锁是兼容的。
InnoDB中的锁
首先会有上面介绍的表级别的共享锁、独占锁,以及意向锁。
表级别的AUTO-INC锁
系统自动给AUTO_INCREMENT修饰的列进行递增赋值的实现方式主要有下面两个
采用AUTO-INC锁,也就是在执行插入语句时就加一个表级别的AUTO-INC锁,然
后为每条待插入记录的AUTO_INCREMENT修饰的列分配递增的值。在该语句执行
结束后,再把AUTO-INC锁释放掉。这样一来,一个事务在持有AUTO-INC锁的过程
中,其他事务的插入语句都要被阻塞,从而保证一个语句中分配的递增值是连续的。如果我们的插入语句在执行前并不确定县体要插入多少条记录,一般是使用AUTO-INC锁为AUTO_INCREMENT修饰的列生成对应的值。
采用一个轻量级的锁,在为插入语句生成AUTO_INCREMENT修饰的列的值时获取这个轻量级锁 然后在生成本次插入语句需要用到的AUTO_INCREMENT修饰的值之后,就把该轻量级锁释放掉 而不需要等到整个插入语句执行完后才释放锁
如果我们的插入语句在执行前就可以确定具体要插入多少条记录,那一般采用轻量级锁的方式对AUTO_INCREMENT修饰的列进行赋值。这种方式可以避免锁定,可以提升插入性能。
InnoDB行级锁
Record Lock:
记录锁,把锁加载一条记录上,这种锁有S锁和X锁之分,和上面介绍的s锁和x锁一样。
Gap Lock
在REPEATABLE READ隔离级别下是可以在很大程度上解决幻读现象。解决方案有两种:使用MVCC方案解决;使用加锁方案解决。但是在使用加锁方案解决时有个大问题,就是事务在第一次执行读取操作时那些幻影记录尚不存在无法给这些幻影记录加上记录锁。因此设计gap锁,这种锁类型的官方名称为LOCK_GAP,也可以简称为gap锁。比如为number值为8的那条记录加一个gap锁。
上图为number值为8的记录加了gap锁,这意味着不允许别的事务在number值为8的记录前面的问隙插入新记录,其实就是number列的值在区间(3,8)的新记录是不允许立即插入的.比如有另外一个事务想插入一条numbe值为4的新记录,首先要定位到该条新记录的下-条记录,也就是number值为8的记录,而这条记录上又有一个gao锁,所以就会阻塞插入操作直到拥有这个gap锁的事务提交了之后将该gap锁释放掉,其它事务才可以插入number列的值在区间(3 8)中的新记录。
这个gap锁的提出仅仅是为了防止插入幻影记录而提出的。虽然gap锁有共享gap锁和独占gap锁这样的说法,但是它们起到的作用都是相同的。而且如果对一条记录加了gap锁(无论是共享gap锁还是独占gap锁)并不会限制其他事务对这条记录加记录锁或者继续加gap锁。再强调一遍gap锁的作用仅仅是为了防止插入幻影记录而已.
不知道大家是否发现了一个问题。给一条记录加gap锁只是不允许其他事务向这条记录前面的间隙插入新记录,那对于最后一条记录之后的间隙,这里时利用数据页里的两条伪记录。
- Infimum记录: 表示该页面中最小的记录
- Supremum记录:表示该页面中最大的记录
如果范围区间包括负无穷或者正无穷,就是给这俩条记录加上gap锁防止插入。
next-key lock
这个是gap锁以及航所的合体,既可以给某条记录加锁也可以给这条记录之前的区间加锁。
Insert Tntention Lock
一个事务在插入一条记录时,需要判断插入位置是否已被别的事务加了gap锁,如果有的话 插入操作需要等待,直到拥有gap锁的那个事务提交为止。但是InnoDB规定事务在等待时也需要在内存中生成一个锁结构,说明有事务想在某个问隙中插入新记录,但是现在处于等待状态。这种锁命名为Insert Tntention Lock。也可以称为插入意向锁。
隐式锁
在内存中生成锁结构并且维护它们并不是一件零成本的事情,设计InnoDB的大叔出于勤俭节约的精神,提出了一个隐式锁的概念。比如一般情况下执行的INSERT语句是不需要在内存中生成锁结构的〈当然,如果即将插入的间隙已经被其他事务加了gap锁,那么本次INSERT操作会阻塞,并且当前事务会在该间隙上加一个插入意向锁)。但是这可能导致一些问题,比方说一个事务首先插入了一条记录(此时并没有与该记录关联的锁结构),然后另一个事务执行的操作会导致修改这条记录,那么就有可能出现赃读的现象。这时InnoDB的做法是,帮助前一个事务建立一个X锁,并且是不阻塞的锁,而事务本身也会建立一个锁,但是处于阻塞状态,等待前一条记录释放。
加锁的情况
普通的SELECT语句
在不通的隔离级别下,普通的SELECT语句具有不通的表现,具体如下
在READ UNCOMMITED隔离级别下,不加锁,直接读取记录的最新版本;可能出现赃读、不可重复读和幻读现象
在READ COMMITED隔离级别下,不加锁;每次执行普通的SELECT语句时都会生成一个ReadView,这样避免了赃读现象,但没有避免不可重复读和幻读显现
在REPEATABLE READ隔离级别下,不加锁;只在第一次执行普通的SELECT语句时生成一个 ReadView,这样就把脏读、不可重复读和幻读现象都避免了.
暂未完结