前言

以下内容是作者在网上搜集和自己总结而来。

一、基本概念

MySQL 事务都是指在 InnoDB 引擎下,MyISAM 引擎是不支持事务的。

事务具有原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)四个特性,简称 ACID,缺一不可。今天要说的就是隔离性。

1.1 脏读

脏读指的是读到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据。读到了并一定最终存在的数据,这就是脏读。

1.2 可重复读

可重复读指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据都是一致的。通常针对数据更新(UPDATE)操作。

1.3 不可重复读

对比可重复读,不可重复读指的是在同一事务内,不同的时刻读到的同一批数据可能是不一样的,可能会受到其他事务的影响,比如其他事务改了这批数据并提交了。通常针对数据更新(UPDATE)操作。

1.4 幻读

幻读是针对数据插入(INSERT)操作来说的。假设事务A对某些行的内容作了更改,但是还未提交,此时事务B插入了与事务A更改前的记录相同的记录行,并且在事务A提交之前先提交了,而这时,在事务A中查询,会发现好像刚刚的更改对于某些数据未起作用,但其实是事务B刚插入进来的,让用户感觉很魔幻,感觉出现了幻觉,这就叫幻读。

二、事务隔离级别

SQL 标准定义了四种隔离级别,MySQL 全都支持。这四种隔离级别分别是:

2.1 读未提交(READ UNCOMMITTED)

最低的事务隔离级别,一个事务还没提交时,它做的变更就能被别的事务看到;

2.2 读提交 (READ COMMITTED)

保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据,可避免脏读的发生,但是可能会造成不可重复读;

2.3 可重复读 (REPEATABLE READ)

多次读取同一范围的数据会返回第一次查询的快照,即使其他事务对该数据做了更新修改。事务在执行期间看到的数据前后必须是一致的,但如果这个事务在读取某个范围内的记录时,其他事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行,这就是幻读;

2.4 串行化 (SERIALIZABLE)

花费最高代价但最可靠的事务隔离级别。

“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行

只有串行化的隔离级别解决了全部这 3 个问题,其他的 3 个隔离级别都有缺陷。
从上往下,隔离强度逐渐增强,性能逐渐变差。采用哪种隔离级别要根据系统需求权衡决定,其中,可重复读是 MySQL 的默认级别。

事务隔离其实就是为了解决上面提到的脏读、不可重复读、幻读这几个问题,下面展示了 4 种隔离级别对这三个问题的解决程度。

只有串行化的隔离级别解决了全部这 3 个问题,其他的 3 个隔离级别都有缺陷。

三、快照读-MVCC

3.1 什么是MVCC

MVCC,全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。

MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读

3.2 什么是快照读

像不加锁的select操作就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但它在很多情况下,避免了加锁操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版本

3.3 快照读的实现方式

MVCC中的核心知识点
(1)事务版本号
每次事务开启前都会从数据库获得一个自增长的事务ID,可以从事务ID判断事务的执行先后顺序。
(2)表的隐藏列
DB_TRX_ID: 记录操作该数据事务的事务ID;
DB_ROLL_PTR:指向上一个版本数据在undo log 里的位置指针;
DB_ROW_ID: 隐藏ID ,当创建表没有合适的索引作为聚集索引时,会用该隐藏ID创建聚集索引;
(3)undo log
Undo log 主要用于记录数据被修改之前的日志,在表信息修改之前先会把数据拷贝到undo log 里,当事务进行回滚时可以通过undo log 里的日志进行数据还原。

(4)read view
在innodb 中每个SQL语句执行前都会得到一个read_view。副本主要保存了当前数据库系统中正处于活跃(没有commit)的事务的ID号,其实简单的说这个副本中保存的是系统中当前不应该被本事务看到的其他事务id列表。
min_trx_id:read view生成时,活跃事务id列表中的最小id
max_trx_id:read view生成时,数据库即将分配的事务id,也就是当前已创建最大事务id+1
  一个事务在对一行数据做读取操作的时候,会从undo log历史版本链中从最新版本开始往前比对,通过一系列的规则,根据快照版本中的trx_id字段和read view来确定该版本对于当前事务是否可见,如果当前比对版本不可见,那么就通过roll_pointer找到上一个版本进行比对,直到找到可见版本或找不到任何一个可见版本。这些规则定义如下:

1.如果 trx_id < min_trx_id,则说明该版本对于当前事务(read view)来说,是已提交事务生成的,那么对于当前事务可见。
2.如果trx_id >= max_trx_id:则说明说明该数据是在当前read view 创建之后才产生的,所以数据不予显示。3.如果min_trx_id =< trx_id < max_trx_id:
这种情况就说明这个数据有可能是在当前事务开始的时候还没有提交的。所以这时候我们需要把数据的事务ID与当前read view 中的活跃事务集合trx_ids 匹配:
情况1: 如果事务ID不存在于trx_ids 集合(则说明read view产生的时候事务已经commit了),这种情况数据则可以显示。
情况2: 如果事务ID存在trx_ids则说明read view产生的时候数据还没有提交,但是如果数据的事务ID等于creator_trx_id ,那么说明这个数据就是当前事务自己生成的,自己生成的数据自己当然能看见,所以这种情况下此数据也是可以显示的。
情况3: 如果事务ID既存在trx_ids而且又不等于creator_trx_id那就说明read view产生的时候数据还没有提交,又不是自己生成的,所以这种情况下此数据不能显示。


思考下面一个问题:

在RC(读已提交)和RR(可重复度)级别下,MVCC都会生效,那么为什么RC不可以解决幻读,而RR可以解决幻读?

     原因: 两种隔离界别下的核心处理逻辑就是判断所有版本中哪个版本是当前事务可见的处理。针对这个问题InnoDB在设计上增加了ReadView的设计,ReadView中主要包含当前系统中还有哪些活跃的读写事务,把它们的事务id放到一个列表中,我们把这个列表命名为为m_ids。以上内容是对于 RR 级别来说,而对于 RC 级别,其实整个过程几乎一样,唯一不同的是生成 ReadView 的时机,RR 级别只在事务开始时生成一次,之后一直使用该 ReadView。而 RC 级别则在每次 select 时,都会生成一个 ReadView。

四、当前读-锁

4.1 锁介绍

当前读是读取的数据库最新的数据,当前读和快照读不同,因为要读取最新的数据而且要保证事务的隔离性,所以当前读是需要对数据进行加锁的,当前读的实现方式就是Next key lock临键锁。

临键锁(Next-key Locks)
临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间

记录锁(Record Locks)
记录锁是 封锁记录,记录锁也叫行锁,例如:
SELECT * FROM student WHERE id=1 FOR UPDATE;
它会在 id=1 的记录上加上记录锁,以阻止其他事务插入,更新,删除 id=1 这一行。

间隙锁(Gap Locks)
间隙锁是封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围.

4.2 产生间隙锁条件

4.3 加锁规则

4.4 案例数据



4.5 临键锁

总结

思考

MVCC真的解决了幻读问题吗?

mysql如何防止幻读相关推荐

  1. mysql 什么是幻读_Mysql中的幻读(一)

    什么是幻读 幻读表示的是在一个事物里面 同一个select语句,前后两次查询出来的结果是不相同的,需要注意的一点是,在InnoDB里面,幻读跟事物的隔离级别有关,更加准确的说是跟一个事物的快照和当前读 ...

  2. mysql数据库出现幻读,MySQL 幻读怎样处理?_数据库

    MySQL 幻读怎样处理? 1.MVCC快照,将历史数据存一份快照,在其事件增添与删除数据时,保证当前事件来说是不可见的: 多半数据库都完成了多版本并发掌握,而且都是靠保留数据快照来完成的. 以 In ...

  3. mysql实战20 | 幻读是什么,幻读有什么问题?

    在上一篇文章最后,我给你留了一个关于加锁规则的问题.今天,我们就从这个问题说起吧. 为了便于说明问题,这一篇文章,我们就先使用一个小一点儿的表.建表和初始化语句如下(为了便于本期的例子说明,我把上篇文 ...

  4. mySql 脏读,幻读,不可重复度与事务隔离级别

    mysql有3种并发问题 脏读 读到未提交的数据 A事务 B事务 开启事务 查询结果100 开启事务 更新到150,未提交 查询结果150 回滚 查询结果100 A事务查询到了B事务未提交的内容.这种 ...

  5. mysql脏读,幻读,不可重复读以及间隙所解决幻读

    1.数据脏读 事务a修改了某条数据,然后事务b读取了事务a修改的该条数据,然后事务a由于某些原因,事务a回滚了,这样事务b读到的数据就和回滚的数据不同了,这时事务b读取的数据就是脏数据.概况一句话就是 ...

  6. mysql java 解决幻读_MySQL 是如何解决幻读的

    MySQL 是如何解决幻读的 一.什么是幻读 在一次事务里面,多次查询之后,结果集的个数不一致的情况叫做幻读. 而多出来或者少的哪一行被叫做 幻行 二.为什么要解决幻读 在高并发数据库系统中,需要保证 ...

  7. mysql 什么是幻读_何为幻读?MySQL又是如何解决幻读的?

    一.什么是幻读 在一次事务里面,多次查询之后,查询的结果集的个数不一致的情况叫做幻读.而多出来或者少的哪一行被叫做 幻行 二.为什么要解决幻读 在高并发数据库系统中,需要保证事务与事务之间的隔离性,还 ...

  8. mysql rr解决幻读吗_mysql rr隔离级别解决幻读了吗

    以下内容全部基于innodb. 虽然下面有很多概念很浅显,但还是要解释一下 什么是幻读? 当一个事务在多次查询中,发现了一行不是在当前事务中添加的数据.出现这种问题就叫做幻读. 关于四种隔离级别 未提 ...

  9. mysql 并没有幻读_MySQL默认隔离级别REPEATABLE-READ并没有解决幻读问题

    刷脉脉,发现一个帖子讨论幻读问题: https://maimai.cn/web/gossip_detail?src=app&webid=eyJhbGciOiJIUzI1NiIsInR5cCI6 ...

  10. 五分钟了解Mysql脏读、幻读、不可重复读、mvcc

    点击上方关注 "终端研发部" 设为"星标",和你一起掌握更多数据库知识 首先对多事务并发的问题的思考 对 innodb引擎执行流程 和 buffer pool ...

最新文章

  1. Linux下使用tee既在屏幕上显示输出,又把输出写进文件
  2. LINQ中的Let关键字
  3. java78条注意事项
  4. apache hadoop_使用Apache Hadoop计算PageRanks
  5. java: 错误: 不支持发行版本 5
  6. windows Server 2003 尝试安装.NET Framework 4 失败
  7. python语言的核心理念是_Python 编程语言的核心是什么?
  8. [解决方案]ln:无法创建符号链接‘ /usr/bin/python‘:权限不够
  9. TelephonyManager与PhoneInterfaceManager应用
  10. java开发冒险岛系统实训报告_樱妖冒险岛079完美源码
  11. 36令牌环网的基本原理
  12. Bryntum Web JavaScript Components Crack
  13. 黑苹果opencore下HD4400打开百度云等软件出现花屏的解决方案
  14. java-net-php-python-jsp固定资产管理系统计算机毕业设计程序
  15. C语言解决狐狸找兔子的问题(数组)
  16. 中国凝油锅炉市场趋势报告、技术动态创新及市场预测
  17. Android studio通过荣耀20调试Android程序
  18. scratch做飞猫躲避飞龙的游戏
  19. 计算机网络体系结构 - 网络安全
  20. C语言链表2(创建新的节点以及尾插法)

热门文章

  1. 迭代期望和方差(iterated expectation,variance)
  2. SPFA与迪杰斯特拉
  3. 迪杰斯特拉算法(图示+C语言实现)
  4. 北京药监局考试计算机操作,考科一电脑操作
  5. 95%以上的日常办事启用电子签章,你都体验过哪些?
  6. 如何删除ie浏览器缓存文件、缓存js
  7. 超详细|开关电源电路图及原理讲解
  8. 舒老师的hu测(日常吐槽)
  9. 高效能人士的七个习惯--由内而外全面造就自己
  10. 屏幕录像专家限制录像时长_屏幕录像档案已更新!