MySql Innodb锁机制

锁概述

undo log版本链 + Read View机制实现的MVCC多版本并发控制,可以防止事务并发读写同一数据时出现的脏读+不可重复读+幻读问题。但除脏读+不可重复读+幻读问题外,并发读写同一数据还有脏写问题。就是当多个事务并发更新同一条数据时,此时就可能会出现脏写问题,如下图示:

一.事务A对数据进行操作,将值修改为A;

二.事务B也对该数据进行操作,将值修改为B;

三.接着事务A进行了回滚,将值恢复成NULL;

四.事务B发现数据值B没有了,出现数据不一致;

脏写:一个事务修改了另一个没提交的事务修改过的值,导致数据可能不一致。因为这个没提交的事务有可能会回滚

锁分类

(1)从操作的粒度可分为表级锁、行级锁和页级锁

(2)从操作的类型可分为读锁和写锁

(3)从操作的性能可分为乐观锁和悲观锁

(1)从操作的粒度可分为表级锁、行级锁和页级锁

一.表级锁:每次操作锁住整张表

锁定粒度最大,发生锁冲突概率最高,并发度最低,应用在MyISAM、InnoDB、BDB存储引擎中。

二.行级锁:每次操作锁住一行数据

锁定粒度最小,发生锁冲突的概率最低,并发度最高,应用在InnoDB存储引擎中。

三.页级锁:每次锁定相邻的一组记录

锁定粒度界于表锁和行锁间,开销和加锁时间界于表锁和行锁间。并发度一般,应用在BDB存储引擎中。

(2)从操作的类型可分为读锁和写锁

一.读锁(S锁):共享锁,行级锁

针对同一份数据,多个读操作可以同时进行而不会互相影响。事务A对记录添加了S锁,可以对记录进行读操作,不能做修改。其他事务可以对该记录追加S锁,但是不能追加X锁。要追加X锁,需要等记录的S锁全部释放。

二.写锁(X锁):排它锁,行级锁

当前写操作没有完成前,它会阻断其他事务的写锁和读锁请求。事务A对记录添加了X锁,可以对记录进行读和修改,其他事务不能对记录进行读和修改。

三.IS锁:意向共享锁,表级锁

已加S锁的表肯定会有IS锁,反过来,有IS锁的表不一定会有S锁。

四.IX锁:意向排它锁,表级锁

已加X锁的表肯定会有IX锁,反过来,有IX锁的表不一定会有X锁。

(3)从操作的性能可分为乐观锁和悲观锁

一.乐观锁

一般的实现方式是对记录数据版本进行对比。在数据库表中有一个version字段,根据该字段进行冲突检测。如果有冲突就提示错误信息,所以乐观锁属于代码层面的锁控制。

二.悲观锁

修改一条数据时,为避免被其他事务同时修改,在修改前先锁定。共享锁和排它锁都是悲观锁的不同实现,属于数据库提供的锁机制。

根据加锁的范围,MySQL的锁可以分为:全局锁、表级锁和行级锁三类。

insert 插入流程

针对于事务当中的一笔 insert 操作,过程中的加锁步骤遵循下述流程:

• 1)申请插入意向锁: 本质上是去检查,插入位置所处范围是否存在间隙锁

• 2)唯一键冲突校验: 校验插入记录是否会和已存在记录发生唯一键冲突(Duplicate Key Conflict)

• 3)插入记录并加锁: 若没有唯一键冲突,则插入记录(草稿态),然后对其加行 X Lock

• 4)针对冲突记录加锁: 若发生唯一键冲突,则对引起冲突的行记录左右空隙加间隙锁,并申请该行记录的 S Lock

• 5)冲突记录双重校验:成功后,需要 double check 冲突记录的合法性,是的话返回唯

死锁案例

基于上述流程,下面分享一个因为 INSERT 操作而引发死锁的案例.

在操作开始前,数据表初始的数据状况如下表所示:

具体执行 SQL 如下表,在时刻 3 事务 B 插入 key = n 时因遭遇唯一键冲突,会对记录加左右间隙锁,并因为申请冲突记录的 S Lock 而陷入阻塞;而事务 A 在时刻 4 尝试插入 key = m 时则会因为事务 B 施加的间隙锁而陷入阻塞,最终形成死锁:

事务 A -> 等待事务 B 释放 key = n 的左右间隙锁

事务 B -> 等待事务 A 释放 key = n 的 X Lock

案例延伸探讨 

针对上述死锁案例,我们额外展开探讨一个细节点:

案例中形成死锁的一个重要原因在于,事务 B 遭遇唯一键冲突后,选择先加间隙锁,再申请冲突记录的 S Lock,正是这样的加锁顺序才导致事务 A 后续的 INSERT 操作发生阻塞,最后引起锁资源的循环依赖.

试想一下,事务 B 在唯一键冲突后不申请间隙锁而是仅加冲突记录的行 S Lock(猜想一) ,亦或是把加锁顺序调整为先加行 S Lock,再加间隙锁(猜想二) ,这样是否就能够规避死锁问题呢?

针对猜想一,我们论证一下加间隙锁的必要性.

通过下述 SQL 我们演示一个不加间隙锁而导致的 badcase:

在时刻 3 事务 B 阻塞等待冲突记录行 S Lock,随后时刻 4 事务 A 回滚,因此事务 B 成功获得该行的 S Lock,并且发现行记录已经被删除,判断唯一键冲突问题已解;但与此同时,一个并发执行的事务 C 在此时见缝插针,又插入了一条唯一键相同的记录,这样就会导致事务 B 针对唯一键冲突的校验结果失准.

针对猜想二,其实存在的问题和猜想一是一样的,就是倘若事务 A 回滚,此时没有有效的手段拦截第三方并发事务的插入行为,因此事务 B 才需要先加间隙锁,阻止其他事务的并发插入行为,再进行后续的加行锁和校验操作.

基于 SQL 展示的反例如下:

  • 28
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值