4 种事务的隔离级别,InnoDB 如何巧妙实现?

栏目: 数据库 · Mysql · 发布时间: 7年前

内容简介:隔离性是指,多个用户的并发事务访问同一个数据库时,一个用户的事务不应该被其他用户的事务干扰,多个并发事务之间要相互隔离。咱们举例子来说明,假设有InnoDB表:

事务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产生的影响,这个影响叫做“ 幻读 ”。

可以看到,并发的事务可能导致其他事务:

  • 读脏

  • 不可重复读

  • 幻读

InnoDB实现了哪几种事务的隔离级别?

按照 SQL 92标准,InnoDB实现了四种不同事务的隔离级别:

  • 读未提交 ( Read Uncommitted )

  • 读提交 ( Read Committed, RC )

  • 可重复读 ( Repeated Read, RR )

  • 串行化 ( 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并发如此高,原因竟然在这? 》中有详细的描述;

(2) 加锁的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,select为啥会阻塞insert? 》。

四,读提交( Read Committed, RC )

这是互联网最常用的隔离级别,在RC下:

(1)普通读是快照读;

(2)加锁的select, update, delete等语句,除了在外键约束检查( foreign-key constraint checking )以及重复键检查( duplicate-key checking )时会封锁区间,其他时刻都只使用记录锁;

此时,其他事务的插入依然可以执行,就可能导致,读取到幻影记录。

总结

  • 并发事务之间相互干扰,可能导致事务出现 读脏 不可重复度 幻读 等问题

  • InnoDB实现了SQL92标准中的四种隔离级别

(1) 读未提交 :select不加锁,可能出现读脏;

(2) 读提交(RC) :普通select快照读,锁select /update /delete 会使用记录锁,可能出现不可重复读;

(3) 可重复读(RR) :普通select快照读,锁select /update /delete 根据查询条件情况,会选择记录锁,或者间隙锁/临键锁,以防止读取到幻影记录;

(4) 串行化 :select隐式转化为select ... in share mode,会被update与delete互斥;

  • InnoDB默认的隔离级别是RR,用得最多的隔离级别是RC

或许有朋友问,为啥没提到insert?可以查阅《 InnoDB并发插入,居然使用意向锁? 》。 

4 种事务的隔离级别,InnoDB 如何巧妙实现?

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

本文新名词颇多,前置文章更精彩:

InnoDB,MVCC,快照读

InnoDB,记录锁,间隙锁,临键锁

InnoDB,B+树的细节

InnoDB与MyISAM索引的差异


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Ajax for Web Application Developers

Ajax for Web Application Developers

Kris Hadlock / Sams / 2006-10-30 / GBP 32.99

Book Description Reusable components and patterns for Ajax-driven applications Ajax is one of the latest and greatest ways to improve users’ online experience and create new and innovative web f......一起来看看 《Ajax for Web Application Developers》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具