MySQL 事务隔离级别

MySQL InnoDB事务的隔离级别有四级,默认是“可重复读”(REPEATABLE READ)。

未提交读(READ UNCOMMITTED)。另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据(脏读)。

提交读(READ COMMITTED)。本事务读取到的是最新的数据(其他事务提交后的)。问题是,在同一个事务里,前后两次相同的SELECT会读到不同的结果(不重复读)。

可重复读(REPEATABLE READ)。在同一个事务里,SELECT的结果是事务开始时时间点的状态,因此,同样的SELECT操作读到的结果会是一致的。但是,会有幻读现象(稍后解释)。

串行化(SERIALIZABLE)。读操作会隐式获取共享锁,可以保证不同事务间的互斥。

四个级别逐渐增强,每个级别解决一个问题。

脏读,最容易理解。另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据。
这个可以通过读已提交解决。

不重复读。解决了脏读后,会遇到,同一个事务执行过程中,另外一个事务提交了新数据,因此本事务先后两次读到的数据结果会不一致。
对当前数据加行锁解决。

幻读。解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。但是,如果另一个事务同时提交了新数据,本事务再更新时,就会“惊奇的”发现了这些新数据,貌似之前读到的数据是“鬼影”一样的幻觉。
通过MVCC+间隙锁解决

MySQL 事务实现原理

事务的实现是基于数据库的存储引擎,不同的存储引擎对事务的支持程度不一样。MySQL 中支持事务的存储引擎有InnoDB 和 NDB。 InnoDB 是高版本 MySQL 的默认的存储引擎,因此就以 InnoDB 的事务实现为例,InnoDB 是通过多版本并发控制(MVCC,Multiversion Concurrency Control )解决不可重复读问题,加上间隙锁(也就是并发控制)解决幻读问题。因此 InnoDB 的 RR 隔离级别其实实现了串行化级别的效果,而且保留了比较好的并发性能。

什么是MVCC?

MVCC 全称是多版本并发控制系统,InnoDB 和 Falcon 存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决幻读问题。

innoDB 的 MVCC 是通过在每行记录后面保存两个隐藏的列来实现,这两个列一个保存了行的创建时间,一个保存行的过期时间(删除时间)。当然存储的并不是真实的时间而是系统版本号(system version number)。每开始一个新的事务,系统版本号都会自动新增,事务开始时刻的系统版本号会作为事务的版本号,用来查询到每行记录的版本号进行比较。

在RR隔离级别下,MVCC的操作如下:

select操作
InnoDB只查找版本早于(包含等于)当前事务版本的数据行。可以确保事务读取的行,要么是事务开始前就已存在,或者事务自身插入或修改的记录。
行的删除版本要么未定义,要么大于当前事务版本号。可以确保事务读取的行,在事务开始之前未删除。

insert操作
将新插入的行保存当前版本号为行版本号。

delete操作
将删除的行保存当前版本号为删除标识。

update操作
insert和delete操作的组合,insert的行保存当前版本号为行版本号,delete则保存当前版本号到原来的行作为删除标识。

这篇文章已经举了例子:
https://www.cnblogs.com/myseries/p/10930910.html

简要把例子概括一下:

第一步:事务A插入3条记录:

innoDB为新插入的每一行保存当前系统版本号作为版本号. 第一个事务ID为1;start transaction;
insert into yang values(NULL,'yang') ;
insert into yang values(NULL,'long');
insert into yang values(NULL,'fei');
commit;

事务A查询结果:select * from yang ;

第二步:事务B插入一条数据

另一个事务ID为3往这个表里插入了一条数据;  第三个事务ID为3;start transaction;
insert into yang values(NULL,'tian');
commit;

事务B的查询结果:

事务A这个时候的查询结果:select * from yang ;

事务A的查询结果没变,因为:
select * from yang ; 这个普通查询语句属于快照读。使用多版本并发控制MVCC保证事务。

InnoDB会根据以下两个条件检查每行记录:
  a.InnoDB只会查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的.
  b.行的删除版本要么未定义,要么大于当前事务版本号,这可以确保事务读取到的行,在事务开始之前未被删除.
 只有a,b同时满足的记录,才能返回作为查询结果.
 

快照读和当前读

当前读:select...lock in share mode (共享读锁)select...for updateupdate , delete , insert
当前读:  
单纯的select操作,不包括上述 select ... lock in share mode, select ... for update。 

第3步:事务C删除并更新了一条数据:

start   transaction;
delete from yang where id=1;
update yang set name='Long' where id=2;
commit;

当前数据库中的实际状态是:

事务A读到的是:select * from yang;

事务A的查询结果没变,因为还是上面的:
select * from yang ; 这个普通查询语句属于快照读。使用多版本并发控制MVCC保证事务。
InnoDB会根据以下两个条件检查每行记录:
  a.InnoDB只会查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的.
  b.行的删除版本要么未定义,要么大于当前事务版本号,这可以确保事务读取到的行,在事务开始之前未被删除.
 只有a,b同时满足的记录,才能返回作为查询结果.

但是如果事务A这个时候用当前读sql去读:select * from yang for update

得到的是当前最新的记录。也就是当前读查询出了其他事务新插入的行。

结论:

对于使用MVCC的可重复读(REPEATABLE READ)隔离级别。普通的快照读,已经解决不可重复读和幻读的问题,同时没有使用锁,并发性能高。但是,快照读读取的都是历史数据,并没有解决当前读情况下的幻读问题:即可以看到其他数据的新增。所以需要通过间隙锁来保证当前读情况下的幻读问题

间隙锁:

间隙锁:只有在Read Repeatable、Serializable隔离级别才有,就是锁定范围空间的数据。

比如:

select * from yang where id>2 for update;
id>2的记录全部被锁住了,其他事务无法更新id>2的所有记录。包括新增id=6的记录。
因为此时如果不锁定没有的数据,例如当加入了新的数据id=6,就会出现幻读,间隙锁避免了幻读。

间隙锁注意事项:

1.对主键或唯一索引,如果当前读时,where条件全部精确命中(=或者in),这种场景本身就不会出现幻读,所以只会加行记录锁。

2.没有索引的列,当前读操作时,会加全表gap锁,生产环境要注意。

3.非唯一索引列,如果where条件部分命中(>、<、like等)或者全未命中,则会加附近Gap间隙锁。例如,某表数据如下,非唯一索引2,6,9,9,11,15。如下语句要操作非唯一索引列9的数据,gap锁将会锁定的列是(6,11],该区间内无法插入数据。

结论:

对于可重复度隔离级别,如果普通读也用间隙锁那就和串行化没有区别了,并发性能很差。所以使用MVCC实现了读的非阻塞,提升了读性能。可是无法避免当前读情况下的幻读,所以加上间隙锁可以手工保证实现不出现幻读。

参考资料:
https://www.cnblogs.com/myseries/p/10930910.html
https://www.cnblogs.com/tiancai/p/12053126.html
http://blog.sina.com.cn/s/blog_499740cb0100ugs7.html
https://www.cnblogs.com/wwcom123/p/10727194.html

mysql如何实现4种事务隔离级别相关推荐

  1. mysql四种事务级别_【MySQL 知识】四种事务隔离级别

    摘要:本篇文章主要是为了对MySQL的四种事务隔离级别的介绍.为了保证数据库的正确性与一致性,数据库事务具有原子性(Atomicity).一致性(Consistency).隔离性(Isolation) ...

  2. js hbs mysql_实例分析MySQL下的四种事务隔离级别

    数据库事务有四种隔离级别: 未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据. 提交读(Read Committed):只能读取到已经提交的数据, ...

  3. mysql四种事务隔离级别

    mysql事务并发问题 ACID什么的就不啰嗦了.mysql多个事务并发的时候,可能会出现如下问题: 1. 更新丢失 即两个事务同时更新某一条数据,后执行的更新操作会覆盖先执行的更新操作,导致先执行的 ...

  4. mysql四种输入_mysql四种事务隔离级别

    mysql事务并发问题 ACID什么的就不啰嗦了.mysql多个事务并发的时候,可能会出现如下问题: 1. 更新丢失 即两个事务同时更新某一条数据,后执行的更新操作会覆盖先执行的更新操作,导致先执行的 ...

  5. 【MySQL】MySQL的四种事务隔离级别

    [MySQL]MySQL的四种事务隔离级别 本文实验的测试环境:Windows 10+cmd+MySQL5.6.36+InnoDB 一.事务的基本要素(ACID) 1.原子性(Atomicity):事 ...

  6. Mysql有四种事务隔离级别,详解脏读、不可重复读、幻读

    Mysql的事务隔离级别 Mysql有四种事务隔离级别,这四种隔离级别代表当存在多个事务并发冲突时,可能出现的脏读.不可重复读.幻读的问题. 脏读 大家看一下,我们有两个事务,一个是 Transact ...

  7. Spring 有几种事务隔离级别?

    Spring 中的事务隔离级别和数据库中的事务隔离级别稍有不同,以 MySQL 为例,MySQL 的 InnoDB 引擎中的事务隔离级别有 4 种,而 Spring 中却包含了 5 种事务隔离级别. ...

  8. Java面试题之Oracle 支持哪三种事务隔离级别

    Oracle 支持三种事务隔离级别: 1.读已提交:(默认) 2.串行化: 3.只读模式 转载于:https://www.cnblogs.com/hujinshui/p/10463883.html

  9. InnoDB的几种事务隔离级别

    前文 首先理解事务的ACID的隔离性 并发带来的问题,脏读 .不可重复读 .幻读 的问题. 脏读: 一个事务读取了另一个事务未提交的数据,导致数据不一致.[事务2未提交] 不可重复读: 一个事务前后两 ...

最新文章

  1. CentOS6.8 Redis5 开机自动启动命令设置
  2. ASP.NET MVC – 样式和布局简介
  3. (转)datagridview 自定义列三步走
  4. SAP2014年最新版本EHP7安装经验分享
  5. pond and pool
  6. 2018年澳门就业情况理想 最新失业率维持1.7%
  7. 实战|QUIC协议助力腾讯业务提速30%
  8. iframe URI钓鱼
  9. css画个框,用CSS绘制带有边框的尖端
  10. Module的加载实现
  11. C# 使用Conditional特性而不是#if条件编译
  12. [游戏开发-学习笔记]菜鸟慢慢飞(12)- Unity3D中LitJson 解析遇到的问题
  13. 使用Docker Swarm来运行服务
  14. 联想 M7400 两种清零方法
  15. 【Spring】源码浅析 - ResponseEntity.ok
  16. Android红外功能模拟触摸鼠标事件唤醒屏幕
  17. 踩坑谷歌浏览器翻译插件自动创建font节点
  18. 三、向SpringCloud注册Service服务(Restful服务)
  19. OpenGL ES 模拟器
  20. 指数函数误差平方和matlab,数值分析与实验数学081 张燃 3080801119).doc

热门文章

  1. 苹果微信多开能装多少个?
  2. 美国金融业监管局严厉批评“SAFT”ICO框架
  3. php的表达爱意的一句代码,爱表达的唯美句子大全 浪漫表达爱意的句子12个字
  4. 网站收录量,反链,关键词排名,权重相关问题
  5. 冒泡排序(BubbleSort)
  6. java实现快速排序法
  7. python能为我们做什么读后感作文_请根据影片《告白》写下自己的观后感!
  8. 简书 android bug记录,记录工作中的Bug
  9. Android中图案解锁的设计原理和实现过程
  10. css6图层 解锁,OpenLayers6实例分析:Layer Spy(图层探查)