MySQL解决幻读详解
简单来说就是通过mvcc + next-key locks 防止幻读
幻读是什么?
当前事务读取了一个范围的记录,另一个事务在该范围内插入了新记录,当前事务再次读取该范围内的记录就会发现新插入的记录,这就是幻读
以下MySQL的隔离界别都是可重复读(RR)
mvcc与next-key分别在什么情况下起作用?
- 在快照读的情况下,会通过mvcc来避免幻读
- 在当前读的情况下,会通过next-key来避免幻读
快照读与当前读
快照读:所有普通的select语句都算快照读,它并不会给表中任何记录做加锁操作,其他事务可以对表中记录做任何改动
当前读:加锁的操作都叫当前读,分为s锁,x锁
共享锁:S锁。在事务要读取一条记录时,需要先获取该记录的S锁
select … lock in share mode
独享锁(排他锁):X锁。事务要改动一条记录时,需要先获取X锁
select … for update、insert、update、delete
S锁与S锁是兼容的;S锁与X锁是不兼容;X锁与X锁也是不兼容。
简单了解下跟防止幻读有关的行级锁
record locks:把当前记录上锁
gap locks:如果当前列具有唯一索引,那么就仅仅是把当前行加锁;只有当前列没有索引或者具有非唯一索引,才会锁定前面的间隙
什么意思呢?
如下例:
CREATE TABLE `user` (`id` int NOT NULL,`score` int DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB;
insert into user values(1,79),(3,91),(6,59);
事务1 | 事务2 | |
---|---|---|
1 |
begin; select * from user where score=91 for update; |
|
2 |
begin; insert into user values(2,98); // 因为gap锁的原因,插入失败 commit; |
|
3 | commit; |
也就是在 id (1, 3) 之间加x锁
而如果把事务1的查询语句改成
select * from user where id=3 for update;
则前面的间隙不会上锁,事务2会成功插入!
next-key locks:就是record locks跟gap locks的组合,既能保护该条记录,又能防止其他事务插入该记录前面的间隙中。
如上述加x锁的区间就变成了 (1, 3]
简单了解下mvcc
具有三个隐藏字段:
DB_TRX_ID:记录最后进行插入、更新操作的事务
DB_ROLL_PTR:滚动指针,指向修改前的记录
DB_ROW_ID:如果没有聚簇索引,该字段会构建聚簇索引(相当于隐藏的自增主键)
readview:会记录当前活跃事务的id范围,根据事务id来判断哪个版本是对当前事务可见的
如下例(还是上面表,默认三条数据):
事务1 | 事务2 | |
---|---|---|
1 |
begin; update user set score=50 where id=1; update user set score=60 where id=1; |
|
2 |
begin; select * from user where id=1; //score=79 |
|
3 | commit; | |
4 |
select * from user where id=1; //score=79 commit; |
为什么?
假设事务1的事务id是100
- **事务1未提交:**事务2在执行select之前会生成一个readview,活跃的只有事务1,该readview的事务范围就是100,在该范围内都不符合要求。根据滚动指针(DB_ROLL_PTR)找之前的版本,直到事务id小于100,也就是找到事务1开启之前的版本,那时的score就是79
DB_TRX_ID(事务id) | id | score | DB_ROLL_PTR(滚动指针) | |
---|---|---|---|---|
1 | 100 | 1 | 60 | 2 |
2 | 100 | 1 | 50 | 3 |
3 | 80(肯定小于100) | 1 | 79 |
- 事务1提交:
- 上述的例子是在MySQL默认隔离级别(RR)下,在该隔离级别下,只在第一次select前生成一个readview。在事务1未提交之前已经生成过了,所以搜索到的score还是79。
- 如果隔离级别是RC,那么第二次select前会再次生成一个readview,那么score就是60
上面内容过一遍后,在回过头来考虑幻读问题,这不就已经解决了嘛!
- 快照读的情况下,通过mvcc来避免幻读
- 当前读的情况下,通过next-key来避免幻读
MySQL解决幻读详解相关推荐
- MySQL幻读详解及解决方法
1. 什么是幻读? 建立一张表如下: 按照下面步骤执行两个事务. 事务1: 事务2: 由此,可以把幻读理解为:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已 ...
- mysql 脏读 不可重复读 幻读_mysql事务隔离级别/脏读/不可重复读/幻读详解
一.四种事务隔离级别 1.1read uncommitted 读未提交 即:事务A可以读取到事务B已修改但未提交的数据. 除非是文章阅读量,每次+1这种无关痛痒的场景,一般业务系统没有人会使用该事务隔 ...
- 不可重复读和幻读详解(必看!!!)
前言:看了很多关于MySQL隔离级别的视频和文章,发现了一个问题,大家都是说,不可重复读是在一个事务中读到了另一个事务提交后修改后的数据,而幻读是一个事务读到了另一个事务中添加并提交后的数据.那么删除 ...
- MySQL锁与脏读、不可重复读、幻读详解
一.MySQL锁 1.锁简介 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的 计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据 ...
- MySQL之幻读的详解、实例及解决办法
事务隔离级别(tx_isolation) mysql 有四级事务隔离级别 每个级别都有字符或数字编号 读未提交 READ-UNCOMMITTED | 0:存在脏读,不可重复读,幻读的问题 读已提交 R ...
- 【MySQL系列5】深入分析MySQL中锁并详解锁解决幻读问题
MySQL锁分析 MySQL系列文章汇总 前言 什么是锁 锁的分类 全局锁 表锁 行锁 共享锁 排他锁 意向锁 各种锁的兼容关系 锁到底锁的是什么 举例猜测 结论 行锁的算法 记录锁(Record L ...
- MySQL中的InnoDB是怎么解决幻读的?
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | Aaron_涛 来源 | blog.csdn. ...
- mysql 快照读 幻读,InnoDB的MVCC如何解决不可重复读和快照读的幻读,当前读用next-key解决幻读...
InnoDB默认的隔离级别是RR(可重复读),可以解决脏读和不可重复读,只解决了快照读情况下的幻读问题,当前读情况下解决幻读问题得靠next-key锁. mysql如何实现避免幻读: 在快照读读情况下 ...
- MySQL 到底是怎么解决幻读的?
作者:LastSun https://www.cnblogs.com/wdy1184/p/10655180.html 一.什么是幻读 在一次事务里面,多次查询之后,结果集的个数不一致的情况叫做幻读.而 ...
最新文章
- mysql 分区指定路径_[数据库]MySQL 指定各分区路径
- bootstrap table教程--使用入门基本用法
- docker 无法正常启动或版本信息会报错 Cannot connect to the Docker daemon at
- SAP Fiori问题排查:Why expand does not work for complex note
- 7z压缩文档的powershell示例
- php 数组的定义方法,PHP中数组定义的几种方法
- ubuntu 16.04 编译android,Ubuntu 16.04 64bit 编译 Android 4.4 源码
- linux命令别名永久生效
- Android之Camera拍照
- python删库命令_python3 删除数据库
- android instance区别,Android singleTask 和singleInstance的区别
- 软件中的快速原型技术
- UINO优锘:数字孪生助力运维工程场景化可视化管理
- LIO-SAM后端中的回环检测及位姿计算
- thinkphp内核家教平台网站源码带手机站
- java后台如何将rgb与16进制颜色进行转换
- 大数据中心显示大屏幕用液晶拼接屏还是led显示屏?
- hibernate 二级缓存 @cache注解
- 手机端怎么限制wifi网速
- 《网安学习之道》预告