innodb如何巧妙的实现事务隔离级别详解

前言

之前的文章mysql锁机制详解中我们详细讲解了innodb的锁机制,锁机制是用来保证在并发情况下数据的准确性,而要保证数据准确通常需要事务的支持,而mysql存储引擎innodb是通过锁机制来巧妙地实现事务的隔离特性中的4种隔离级别。

事务ACID特性,其中I代表隔离性(Isolation)。隔离性是指,多个用户的并发事务访问同一个数据库时,一个用户的事务不应该被其他用户的事务干扰,多个并发事务之间要相互隔离。

我们都知道事务的几种性质,数据库中的一致性和隔离性等是实现事务的基本思想,在系统有大量的并发访问的情况下,了解和熟练应用数据库的本身的事务隔离级别,对于写出健壮性,并发处理能力强的代码还是起关键的作用。

1. 事务之间如何互相干扰

一个事务是如何干扰其他事务呢?举个例子,有如下表:

create table lock_example(id smallint(10),name varchar(20),primary key id)engine=innodb;

表中有如下数据:

1, zhangsan
2, lisi
3, wangwu

demo1:

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

insert into t values(4, 'zhaoliu');

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

select * from t;

如果事务B能够读取到(4, zhaoliu)这条记录,说明事务A就对事务B产生了影响,这种影响叫做“读脏”,即读到了未提交事务操作的记录。

demo2:

事务A,先执行:

select * from t where id=1;

结果集为

1,zhangsan

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

update t set name=xxx where id=1;

commit;

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

select * from t where id=1;

结果集为:

1, xxx

这次是已提交事务B对事务A产生的影响,这种影响叫做“不可重复读”,即一个事务内相同的查询,却得到了不同的结果。

demo3:

事务A,先执行:

select * from t where id>3;

结果集为:

NULL

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

insert into t values(4, zhaoliu);

commit;

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

insert into t values(4, xxoo);

结果集为:

Error : duplicate key!

你可能会想。。。你TM在逗我?查了id>3为空集,insert id=4时又告诉我PK冲突?→_→

这次是已提交事务B对事务A产生的影响,这种影响叫做“幻读”。

如上,并发的事务可能导致其他事务出现读脏、不可重复读、幻读。为了避免如上情况出现,innodb又做了哪些努力呢?

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

InnoDB实现了四种不同事务的隔离级别:

  • 读未提交(Read Uncommitted)
  • 读提交(Read Committed, RC)
  • 可重复读(Repeated Read, RR)
  • 串行化(Serializable)

不同事务的隔离级别,实际上是一致性与并发性的一个权衡与折衷。

3. 四种事务的隔离级别,innodb如何实现?

InnoDB使用不同的锁策略(Locking Strategy)来实现不同的隔离级别。

a. 读未提交(Read Uncommitted)

这种事务隔离级别下,select语句不加锁,也不是快照读。

SELECT statements are performed in a nonlocking fashion.

此时,可能读取到不一致的数据,即“读脏”。这是并发最高,一致性最差的隔离级别。

b. 读提交(Read Committed, RC)

  • 普通select是快照读;
  • 加锁的select, update, delete等语句,除了在外键约束检查(foreign-key constraint checking)以及重复键检查(duplicate-key checking)时会封锁区间,其他时刻都只使用记录锁;
  • 间隙锁(gap lock)、临建锁(next-key lock)在该级别下失效;

此时,其他事务的插入依然可以执行,就可能导致,读取到幻影记录。该级别是最常使用的。而且如果是不上锁的select,可能产生不可重复读。

该级别下是通过快照读来防止读脏的。因为在该级别下的快照读总是能读到最新的行数据快照,当然,必须是已提交事务写入的,所以可能产生不可重复读。

c. 可重复读(Repeated Read, RR)

这是InnoDB默认的隔离级别,在RR下:

  • 普通的select使用快照读(snapshot read),这是一种不加锁的一致性读(Consistent Nonlocking Read),底层使用MVCC来实现;
  • 加锁的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);
  • 范围查询条件或者是非唯一索引,会使用间隙锁与临键锁,锁住索引记录之间的范围,避免范围间插入记录,以避免产生幻影行记录,以及避免不可重复读;

在该级别下

  • 通过快照读以及锁定区间来实现避免产生幻读和不可重复读;
  • 某个事务首次read记录的时间为T,未来不会读取到T时间之后已提交事务写入的记录,以保证连续相同的read读到相同的结果集,这可以防止不可重复读;
  • RR下是通过间隙锁,临键锁来解决幻影读问题;

d. 串行化(Serializable)

这种事务的隔离级别下,所有select语句都会被隐式的转化为select ... in share mode,也就是默认上共享读锁(S锁)。

所以,如果事务A先执行如下sql之后,会尝试获取所查询行的IS锁(和别的IS、IX锁是兼容的),这时别的事务也能获取这些行的IS锁甚至是S锁,但是如果接下来,事务A如果update或delete其中的某些行,这时就获取了X锁,别的事务即便是执行普通的select语句也会阻塞,因为它们尝试获取IS锁,但是IS锁和X锁是互斥的,这样就避免了读脏、不可重复读以及幻读,所有事务就只能串行了。

select ... ;

这是一致性最好的,但并发性最差的隔离级别。高并发量的场景下,几乎不会使用上述a和d这两种隔离级别。

4. 总结

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

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

  • 读未提交:select不加锁,可能出现读脏;
  • 读提交(RC):普通select快照读,锁select /update /delete 会使用记录锁,可能出现不可重复读;
  • 可重复读(RR):普通select快照读,锁select /update /delete 根据查询条件等情况,会选择记录锁,或者间隙锁/临键锁,以防止读取到幻影记录;
  • 串行化:select隐式转化为select ... in share mode,会被update与delete互斥;

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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • MySQL 四种事务隔离级别详解及对比

    MySQL 四种事务隔离级别详解及对比 按照SQL:1992 事务隔离级别,InnoDB默认是可重复读的(REPEATABLE READ).MySQL/InnoDB 提供SQL标准所描述的所有四个事务隔离级别.你可以在命令行用--transaction-isolation选项,或在选项文件里,为所有连接设置默认隔离级别. 例如,你可以在my.inf文件的[mysqld]节里类似如下设置该选项: transaction-isolation = {READ-UNCOMMITTED | READ-CO

  • MySQL中Innodb的事务隔离级别和锁的关系的讲解教程

    前言: 我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力.所以对于加锁的处理,可以说就是数据库对于事务处理的精髓所在.这里通过分析MySQL中InnoDB引擎的加锁机制,来抛砖引玉,让读者更好的理解,在事务处理中数据库到底做了什么. 一次封锁or两段锁? 因为有大量的并发访问,为了预防死锁,一般应用中推荐使用一次封锁法,就是在方法的开始阶段,已经预先知道会

  • MySQL四种事务隔离级别详解

    本文实验的测试环境:Windows 10+cmd+MySQL5.6.36+InnoDB 一.事务的基本要素(ACID) 1.原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节.事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样.也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位. 2.一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 .比如A向B转账,不可能A扣了钱,

  • MySQL数据库事务隔离级别介绍(Transaction Isolation Level)

    数据库隔离级别有四种,应用<高性能mysql>一书中的说明: 然后说说修改事务隔离级别的方法: 1.全局修改,修改mysql.ini配置文件,在最后加上 复制代码 代码如下: #可选参数有:READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE. [mysqld] transaction-isolation = REPEATABLE-READ 这里全局默认是REPEATABLE-READ,其实MySQL本来默认也是这个级别

  • 深入解析MySQL的事务隔离及其对性能产生的影响

    SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的.低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销. Read Uncommitted(读取未提交内容)        在该隔离级别,所有事务都可以看到其他未提交事务的执行结果.本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少.读取未提交的数据,也被称之为脏读(Dirty Read). Read Committed(读取提交内容)        这是大多数数据库系统的默认隔离

  • 通过实例分析MySQL中的四种事务隔离级别

    前言 在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别.数据库事务的隔离级别有4个,下面话不多说了,来一起看看详细的介绍吧. 数据库事务有四种隔离级别: 未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据. 提交读(Read Committed):只能读取到已经提交的数据,Oracle等多数数据库默认都是该级别. 可重复读(Repeated Read):可重复读.在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级

  • MySQL数据库事务隔离级别详解

    数据库事务隔离级别 数据库事务的隔离级别有4个,由低到高依次为 Read uncommitted:允许脏读. Read committed: 防止脏读,最常用的隔离级别,并且是大多数数据库的默认隔离级别. Repeatable read:可以防止脏读和不可重复读. Serializable:可以防止脏读,不可重复读取和幻读,(事务串行化)会降低数据库的效率. 这四个级别可以逐个解决脏读 .不可重复读 .幻读 这几类问题. √: 可能出现 ×: 不会出现 事务级别 脏读 不可重复读 幻读 Read

  • innodb如何巧妙的实现事务隔离级别详解

    前言 之前的文章mysql锁机制详解中我们详细讲解了innodb的锁机制,锁机制是用来保证在并发情况下数据的准确性,而要保证数据准确通常需要事务的支持,而mysql存储引擎innodb是通过锁机制来巧妙地实现事务的隔离特性中的4种隔离级别. 事务ACID特性,其中I代表隔离性(Isolation).隔离性是指,多个用户的并发事务访问同一个数据库时,一个用户的事务不应该被其他用户的事务干扰,多个并发事务之间要相互隔离. 我们都知道事务的几种性质,数据库中的一致性和隔离性等是实现事务的基本思想,在系

  • MySql学习笔记之事务隔离级别详解

    背景 说的事务,大家应该都不陌生,开发用到 MySql 数据库的时候,通常会用到事务.其中比较经典的例子就是转账,比如你要给小明转 50 块钱,而此时你的银行卡也就只有 50 块钱. 对于转账过程在代码程序里会有一系列的操作,比如查询账户余额.余额加减.更新余额等,这些操作必须保证是一起处理的,不然等程序查完之后,如果账号 50 块钱还在,然后再给另外一个朋友转账,如果银行也处理的话,没有保证整个流程数据一致性的话,这不就乱套了吗?这时就要用到"事务"了. 事务介绍 简单来说,事务就是

  • MySQL事务隔离机制详解

    目录 前言 一.什么是数据库事务 二.事务并发带来的4类问题 三.事务4种隔离级别 四.Mysql演示4种隔离级别 总结 参考文章: 前言 如何控制并发是数据库领域中非常重要的问题之一,MySQL为了解决并发带来的问题,设计了事务隔离机制.锁机制.MVCC机制,用一整套机制来解决并发问题,本文主要介绍事务隔离机制. 一.什么是数据库事务 事务transaction(简写tx),在数据库中,事务是指一组逻辑操作,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位.事务由事务开始与结束之

  • mysql隔离级别详解及示例

    目录 mysql的4种隔离级别 创建数据表: 设置隔离级别 只是单纯知道事物的隔离级别,但是从未操作过 今日操作一次. 脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的. 不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据. 幻读(Phantom Read):在一个事务的两次查询中数

  • Java Spring事务的隔离级别详解

    目录 引言 数据库访问的并发性问题 事务的隔离级别 悲观锁和乐观锁 总结 引言 之前关于事务的文章已介绍了事务的概念以及事务的四个属性(ACID),相信你对事务应该有所认识和了解. 本篇文章是关于事务的隔离性,介绍数据库提供的多种隔离级别. 数据库访问的并发性问题 所谓事务的隔离性,其实事务的这个属性是针对数据库访问的并发性问题而言的. 那何谓数据库访问的并发性问题呢? 所谓数据库访问的并发性问题是指多个事务可以同时访问数据库中的数据,而当多个事务在数据库中并发执行(同时执行)时,数据的一致性可

  • mysql数据库隔离级别详解

    目录 隔离级别 一.mysql有四个事务隔离级别 二.为什么默认RR隔离级别? 三.RR隔离级别下手动加锁解决幻读理论基础 脏读.不可重复读.幻读 及其解决方法 事务隔离级别命令行操作 操作验证 一.实现脏读 二.操作验证--实现不可重复读 三.操作验证--解决不可重复读 四.操作验证--实现幻读 总结 隔离级别 一.mysql有四个事务隔离级别 每个级别都有字符或数字编号 读未提交 READ UNCOMMITTED | 0 : 存在脏读,不可重复度,幻读的问题. 读已提交 READ COMMI

随机推荐