小白学习mysql 之 innodb locks

Innodb 锁类型:

说明:本文中如无特殊说明,默认为innodb引擎,事务隔离级别为RR。事务

Shared and Exclusive Locks

innodb 能够经过两种方式实现行级锁定,即Shared(S) lock和Exclusive Lock (X)。如下简称为S锁和X锁。资源

S锁为共享锁,持有S锁的事务能够对该行进行读取操做,且其余session对该行不可修改。

X锁为排他锁,持有X锁的事务能够对该行进行修改操做。

若是一条记录被加了S锁,那么其余事务仍能够对其加S锁。
若是一条记录被加了X锁,那么其余事务不能够对其余加S锁或者X锁。

下面一些状况会加S锁:

select ... lock in share mode , insert select ( select 中扫描到的记录), update 连表更新中不进行更新的表 ,
IF EXISTS(select 中扫描到的记录 ) ,使用外键时会对父键进行锁定 ...

下面一些状况会加X锁:

select ... for update , update 中要更新的内容 ...

S锁和X锁对相同记录的加锁必定要保持合理的顺序,不然会很容易形成死锁。

另外,从支持资源并发的角度出发,写各类语句必定要注意扫描的记录数,不只仅是效率问题,更重要的是资源的利用最大化。

正确的认识X锁和S锁,对于资源的利用以及死锁查找是很是重要的。

Intention Locks

意向锁主要是为了支持多粒度锁机制而存在的一种锁,它不是由程序员去用程序控制,而是mysql本身来控制的。

举个例子来讲明mysql的意向锁:

商场的一卫生间每晚都要进行锁门,清洁工大爷天天锁门前先进去挨个检查下了五个隔断是否有人,没有人了方可把卫生间落锁。
大爷以为天天都要这样检查太麻烦,有没有一种办法我在门外都知道里面有没有人?有一天他终于想到了一个办法,他在门外挂了一个牌子,
正面写着“没人”,反面写着“有人”,并且他给全部上卫生间的人两条准则:

1 进入卫生间前,若是牌子是“没人”,那么必定要把牌子翻过来(“有人”)。
2 离开卫生间后,要检查下5个隔断,若是有人就直接离开,没人了要把牌子翻过来(“没人”)。

传说全部人都这样作了,而后老大爷晚上锁门的时候直接看下门口的牌子就能够决定锁门与否,不再用本身进去检查了。

在上面的例子中,假设卫生间是一个数据表,里面的每个隔断是一个数据行,那么卫生间门外的牌子就是意向锁。

Record Locks

Record lock是锁在索引上的,即便没有数据表没有索引,mysql会锁定聚簇索引。

Gap Locks

gap锁锁住的是索引的间隙,主要为了防止幻读的发生。

例如:有一表名为gap,里面有字段c2,c2上有索引(非惟一索引),目前c2有值为 2,4,7,10,几个值。

如今开启一个链接:

1 开始事务

2 更新c2值为4的记录 : update gap set remark = 'change' where c2 = 7;

(事务未提交)

如今开启另一个链接:

1 开启一个事务

2 此时,测试会发现

> insert gap(c2, remark)  values(3,'');
// success

> insert gap(c2, remark)  values(5,'');
//block

> insert gap(c2, remark)  values(8,'');
//block

能够看出,在更新c2=7的记录时,(4,7) 与 (7,10)之间的记录都被锁住了,不能进行插入。

如今,若是把c2的索引修改成惟一索引,再次执行上面的例子,结果又会不同,上面的三条记录所有均可以插入。
所以,在惟一索引上加锁是不会产生gap锁的。在生产中,若是使用for update 进行记录锁定时,where后尽可能使用unique字段。

RR级别下,能够经过设置系统变量innodb_locks_unsafe_for_binlog来使Gap lock 禁用(在查询或者索引被扫描的时候)。

另外,若是删除或者更新的记录是经过惟一键进行扫描的时候,将不会有gap锁产生。(所以,在进行对记录的更改时,where后面最好用主键或者惟一键扫描,避免gap锁)

Next-Key Locks

next-key lock = record lock + gap lock;

相关文章
相关标签/搜索