MySQL-InnoDB究竟如何巧妙实现,4种事务的隔离级别(收藏)

事务ACID特性,其中I代表隔离性(Isolation)
 
什么是事务的隔离性?
隔离性是指,多个用户的并发事务访问同一个数据库时,一个用户的事务不应该被其他用户的事务干扰,多个并发事务之间要相互隔离。
 
一个事务怎么会干扰其他事务呢?
咱们举例子来说明,假设有InnoDB表:

t(id PK, name);

 
表中有三条记录:

1, shenjian

2, zhangsan

3, lisi

 
case 1:读脏
事务A,先执行,处于未提交的状态:

insert into t values(4, wangwu);

 
事务B,后执行,也未提交:

select * from t;

 
如果事务B能够读取到(4, wangwu)这条记录,事务A就对事务B产生了影响,这个影响叫做“读脏”,读到了未提交事务操作的记录。
 
case 2:不可重复读
事务A,先执行:

select * from t where id=1;

 
结果集为:

1, shenjian

 
事务B,后执行,并且提交:

update t set name=xxoo where id=1;

commit;

 
事务A,再次执行相同的查询:

select * from t where id=1;

 
结果集为:

1, xxoo

 
这次是已提交事务B对事务A产生的影响,这个影响叫做“不可重复读”,一个事务内相同的查询,得到了不同的结果。
 
case 3:幻读
事务A,先执行:

select * from t where id>3;

 
结果集为:

NULL

 
事务B,后执行,并且提交:

insert into t values(4, wangwu);

commit;

 
事务A,首次查询了id>3的结果为NULL,于是想插入一条为4的记录:

insert into t values(4, xxoo);

 
结果集为:

Error : duplicate key!

 
事务A的内心OS是:你TM在逗我,查了id>3为空集,insert id=4告诉我PK冲突?
 
这次是已提交事务B对事务A产生的影响,这个影响叫做“幻读”。
 
可以看到,并发的事务可能导致其他事务:
(1)读脏;
(2)不可重复读;
(3)幻读;
 
InnoDB实现了哪几种事务的隔离级别?
按照SQL92标准,InnoDB实现了四种不同事务的隔离级别:
(1)读未提交(Read Uncommitted);
(2)读提交(Read Committed, RC);
(3)可重复读(Repeated Read, RR);
(4)串行化(Serializable);
 
不同事务的隔离级别,实际上是一致性与并发性的一个权衡与折衷
 
InnoDB的四种事务的隔离级别,分别是怎么实现的?
InnoDB使用不同的锁策略(Locking Strategy)来实现不同的隔离级别。
 
一,读未提交(Read Uncommitted)
这种事务隔离级别下,select语句不加锁。
画外音:官方的说法是

SELECT statements are performed in a nonlocking fashion.

 
此时,可能读取到不一致的数据,即“读脏”。这是并发最高,一致性最差的隔离级别。
 
二,串行化(Serializable)
这种事务的隔离级别下,所有select语句都会被隐式的转化为select ... in share mode.
 
这可能导致,如果有未提交的事务正在修改某些行,所有读取这些行的select都会被阻塞住。
画外音:官方的说法是

To force a plain SELECT to block if other transactions have modified the selected rows.

 
这是一致性最好的,但并发性最差的隔离级别。
 
互联网大数据量,高并发量的场景下,几乎不会使用上述两种隔离级别
 
三,可重复读(Repeated Read, RR)
这是InnoDB默认的隔离级别,在RR下:
 
(1)普通的select使用快照读(snapshot read),这是一种不加锁的一致性读(Consistent Nonlocking Read),底层使用MVCC来实现,具体的原理在《InnoDB并发如此高,原因竟然在这?》中有详细的描述;
 
(3)加锁的select(select ... in share mode / select ... for update), update, delete等语句,它们的锁,依赖于它们是否在唯一索引(unique index)上使用了唯一的查询条件(unique search
condition)
,或者范围查询条件(range-type search condition)
    - 在唯一索引上使用唯一的查询条件,会使用记录锁(record lock),而不会封锁记录之间的间隔,即不会使用间隙锁(gap lock)与临键锁(next-key lock)
    - 范围查询条件,会使用间隙锁临键锁,锁住索引记录之间的范围,避免范围间插入记录,以避免产生幻影行记录,尽量避免不可重复的读
画外音:这一段有点绕,多读几遍。
 
关于记录锁,间隙锁,临键锁的更多说明,详见《InnoDB的七种锁》。
 
四,读提交(Read Committed, RC)
这是互联网最常用的隔离级别,在RC下:
 
(1)普通读是快照读;
 
(2)加锁的select, update, delete等语句,除了在外键约束检查(foreign-key constraint checking)以及重复键检查(duplicate-key checking)时会封锁区间,其他时刻都只使用记录锁;
 
此时,其他事务的插入依然可以执行,就可能导致,读取到幻影记录。
 
总结
(1)并发事务之间相互干扰,可能导致事务出现读脏不可重复度幻读等问题;
(2)InnoDB实现了SQL92标准中的四种隔离级别;
- 读未提交:select不加锁,可能出现读脏;
- 读提交(RC):普通select快照读,锁select /update /delete 会使用记录锁,可能出现不可重复读;
- 可重复读(RR):普通select快照读,锁select /update /delete 根据查询条件情况,会选择记录锁,或者间隙锁/临键锁,以防止读取到幻影记录;
- 串行化select隐式转化为select ... in share mode,会被update与delete互斥;
(3)InnoDB默认的隔离级别是RR,用得最多的隔离级别是RC;
 
或许有朋友问,为啥没提到insert?它使用的是插入意向锁,具体详见InnoDB的七种锁》。

架构师之路-分享可落地的架构文章

 
相关文章:
InnoDB并发如此高,原因竟然在这?
InnoDB的七种锁
InnoDB索引,终于懂了
画外音:本文内容基于MySQL5.6,为了避免误传,多处带入了MySQL官网英文。
 
码字不易,谢

发布者:糖太宗,转载请注明出处:https://www.qztxs.com/archives/science/technology/6631

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年5月14日 上午12:34
下一篇 2022年5月14日 上午12:37

相关推荐

  • 虽然小象被淘汰了,但我学会了这种O(n)的排序算法

    时间复杂度为O(n)的排序,除了昨天介绍的基数排序(Radix Sort),还有计数排序(Counting Sort)。   计数排序的适用范围? 待排序的元素在某一个范围[MIN, MAX]之间。 画外音:很多业务场景是符合这一场景,例如uint32的数字排序位于[0, 2^32]之间。   计数排序的空间复杂度? 计数排序需要一个辅助空间,空间大小为O(...

    2022年5月11日
    2200
  • 全网显示 IP 归属地,是怎么实现的

    上个星期开始,微博、抖音、公众号等多个平台纷纷上线了 IP 归属地功能。 我想很多小伙伴会好奇互联网平台商们是怎么通过 IP 定位到我们所属地区的?这背后的原理是什么?IP 归属地背后又有哪些实际的应用? 所以,今天我们就来聊聊 IP 归属地背后的技术原理。 如何通过 IP 找到地址? 在我们印象中,我们都知道可以通过 IP 地址找到某个人。但当我们细想一下...

    2022年5月18日
    5200
  • Spring 源码(16)Spring Bean的创建过程(7)属性填充

    知识回顾 上一篇介绍了Spring中三级缓存的singletonObjects、earlySingletonObjects、singletonFactories,Spring在处理循环依赖时在实例化后属性填充前将一个lambda表达式放在了三级缓存中,后续在获取时进行了判断,如果不需要进行对象代理,那么直接返回对象Bean,然后将三级缓存中的对象删除,然后放...

    2022年5月22日
    3200
  • 服务之间通过缓存传递数据,我坚决反对!

    数据的移动,需要载体,DB和cache是常见的数据存储载体。 如上图: (1)service-A将数据放入cache; (2)service-B从cache里读取数据; cache作为数据存储载体的好处是: (1)cache的读取和写入都非常快; (2)service-A和service-B物理上解耦; 那么问题来了: (1)你遇到过这种“服务之间通过缓存传...

    2022年5月12日
    2500
  • 什么事Spark(轻松学习 Spark)

    今天给大家分享一篇 Spark 核心知识点的梳理,对知识点的讲解秉承着能用图解的就不照本宣科地陈述,力求精简、通俗易懂。希望能为新手的入门学习扫清障碍,从基础概念入手、再到原理深入,由浅入深地轻松掌握 Spark。 1、初识 Spark Spark不仅能够在内存中进行高效运算,还是一个大一统的软件栈,可以适用于各种各样原本需要多种不同的分布式平台的场景。 背...

    2022年5月22日
    7700

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信