Mysql锁类型

1.1 锁的类型

共享锁(读锁),允许事务读一行数据。
排他锁(写锁),允许事务删除或更新一行数据。

1.2 粒度锁

Lock锁根据粒度主要分为表锁、页锁和行锁。MySQL 不同的存储引擎支持不同的锁机制:
MyISAMMEMORY 存储引擎采用的是表级锁(table-level locking)
BDB 存储引擎采用的是页面锁(page-level locking),但也支持表级锁
InnoDB 存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。

1.3 总结
  1. 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
  2. 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
  3. 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

2. InnoDB中的锁

2.1 行锁

InnoDB 实现了以下两种类型的行锁:

共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。

2.2 意向锁

为了支持多粒度锁定,InnoDB 存储引擎引入了意向锁(Intention Lock),每次加行锁前都会加意向锁。意向锁是表级锁目的是在锁定该表前不必检查各个行的行锁,而只需检查表上的意向锁。可以知道RR隔离级别下的表锁有4钟(S、X、IS、IX)。

意向共享锁(IS):事务想要在获得表中某些记录的共享锁,需要在表上先加意向共享锁。
意向互斥锁(IX):事务想要在获得表中某些记录的互斥锁,需要在表上先加意向互斥锁。

意向锁是 innodb 自动加的,不需要用户干预。对于 update、delete 和 insert 语句,innodb 会自动给涉及数据集加排它锁(X);对于普通 select 语句,innodb 不会加任何锁。事务可以通过以下语句显式给记录集加共享锁或排它锁。

共享锁(S):select * from table_name where … lock in share mode。
排它锁(X): select * from table_name where … for update。

表级锁的兼容性

当前锁模式/是否兼容/请求锁模式XIXSIS
X冲突冲突冲突冲突
IX冲突兼容冲突兼容
S冲突冲突兼容兼容
IS冲突兼容兼容兼容
  1. S是的(不是行的)共享锁,X是的(不是行的)排它锁。
  2. 意向锁和意向锁不冲突,意向锁和行锁不冲突。
2.3 MVCC行级锁和一致性非锁定读(consistent nonlocking read)

InnoDB采用多版本并发控制(MVCC, multiversion concurrency control)来增加读操作的并发性。MVCC是指,InnoDB使用基于时间点的快照来获取查询结果,读取时在访问的表上不设置任何锁,因此,在事务T1读取的同一时刻,事务T2可以自由的修改事务T1所读取的数据。这种读操作被称为一致性非锁定读。这里的读操作就是普通SELECT。

隔离级别为RU和Serializable时不需要MVCC,因此,只有RC和RR时,才存在MVCC,才存在一致性非锁定读。

  1. RC隔离级别,每次select都是获取一个最新的快照(所以,RC时总是可以读取到最新提交的数据)。
  2. RR隔离级别,同一个事务内的所有的一致性读总是读取该事物下第一个select获得的快照。
2.4 锁定读(locking read)

InnoDB提供两种锁定读,即:SELECT … FOR SHARE 和 SELECT … FOR UPDATE。

使用这两种锁定读查询数据时会设置排它锁或共享锁。此外,如果当前隔离级别是RR,它还会在每个索引记录前面的间隙上设置排它的或共享的gap lock(排它的和共享的gap lock没有任何区别,二者等价)。

2.3 InnoDB 行锁实现方式
  1. InnoDB 行锁是通过给索引上的索引项加锁来实现的。只有通过索引条件检索数据,InnoDB 才使用行级锁,否则,InnoDB 将使用表锁。
  2. 不论是使用主键索引、唯一索引或普通索引,InnoDB 都会使用行锁来对数据加锁。

3. Record Lock(记录锁)

单个行记录上的锁,Record Lock总是会去锁住索引记录,如果InnoDB存储引擎表建立的时候没有设置任何一个索引,这时InnoDB存储引擎会创建隐藏的聚集索引,并使用该索引执行记录锁。
LOCK_MODES,REC_NOT_GAPX,REC_NOT_GAP

4. Gap Lock(间隙锁)

索引记录之间的间隙上的锁,锁定尚未存在的记录,即索引记录之间的间隙。间隙锁一定是开区间,间隙锁在本质上是不区分共享间隙锁或互斥间隙锁的,而且间隙锁是不互斥的。
gap lock存在的唯一目的就是阻止其他事务向gap中插入数据行,它用于在隔离级别为RR时,阻止的幻读的产生
LOCK_MODES,GAPX,GAP

  • 对于唯一索引
    • 等值检索:Next-Key Locks就退化为记录锁,不会加gap锁。
    • 范围检索:会锁住检索范围内的记录锁和gap锁。
  • 非唯一索引
    • 等值检索:记录锁,索引记录之间的间隙。
    • 范围检索:范围的记录锁和范围内索引记录之间的间隙。
  • 非索引:全表gap锁和记录锁。

5. Next-Key Lock(临键锁)

它锁定索引记录以及该索引记录前面的间隙,是一个左开右闭的区间,有shard或exclusive两种模式。在Repeatable Read隔离级别下,Next-key Lock 算法是默认的行记录锁定算法。
LOCK_MODESX

6. Insert Intention Locks(插入意向锁)

一种特殊的gap lock。在插入操作之前,INSERT操作会首先在索引记录之间的间隙上设置insert intention lock,该锁的范围是(插入值, 向下的一个索引值)。有shard或exclusive两种模式,但,两种模式没有任何区别,二者等价。

LOCK_MODES,GAP,INSERT_INTENTIONX,GAP,INSERT_INTENTION

  1. gap lock会阻塞insert intention lock,事务执行一个语句后生成gap lock后在gap lock区间执行插入语句会阻塞。事实上,gap lock的存在只是为了阻塞insert intention lock。
  2. gap lock相互不会阻塞。
  3. insert intention lock相互不会阻塞。
  4. insert intention lock不会阻塞gap lock。

3. 优化

  1. 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁。
  2. 合理设计索引,尽量缩小锁的范围。
  3. 尽可能较少检索条件,避免间隙锁。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值