mysql怎么解决幻读问题(详解MySQL幻读及如何消除)
mysql怎么解决幻读问题
详解MySQL幻读及如何消除这是一篇数据库隔离级别的科普文章,旨在了解数据库中著名的幻读现象,为了专注,对脏读、不可重复读不作讨论。
事务隔离级别
mysql有四级事务隔离级别:
读未提交 read-uncommitted: 存在脏读,不可重复读,幻读的问题
读已提交 read-committed:不存在脏读,但存在不可重复读,幻读问题
可重复读 repeatable-read:不存在脏读,不可重复读问题,但存在幻读问题
序列化serializable:解决脏读,不可重复读,幻读问题,但完全串行执行,性能最低
什么是幻读
幻读错误的理解:说幻读是事务a 执行两次 select 操作得到不同的数据集,即 select 1 得到10条记录,select 2 得到11条记录。这其实并不是幻读,这是不可重复读的一种,只会在 r-u r-c 级别下出现,而在 mysql 默认的 rr 隔离级别是不会出现的。
这里给出我对幻读的理解:
幻读,并不是说事务中多次读取获取的结果集不同,幻读更重要的是某次的 select 操作得到的结果集所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 记录不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,如同产生了幻觉
举个例子可能会简化理解:
|
mysql> show create table user \g *************************** 1. row *************************** table : user create table : create table ` user ` ( `id` int (11) not null , ` name ` varchar (32) default null , primary key (`id`) ) engine=innodb default charset=utf8 |
分别开启两个事务t1 & t2,并设置其隔离级别为reaptable-read:
t1:
|
mysql> set global transaction isolation level repeatable read ; mysql> begin ; mysql> select * from user ; mysql> insert into user values (1, 'jeff' ); error 1062 (23000): duplicate entry '1' for key 'primary' mysql> select * from user ; |
t2:
|
mysql> set global transaction isolation level repeatable read ; mysql> begin ; mysql> insert into user values (1, 'jeff' ); mysql> commit ; |
t1 事务检测表中是否有 id 为 1 的记录,没有则插入
t2 插入干扰记录,造成t1出现幻读。
上例中需要确保t1事务执行begin后才开始执行事务t2。
上例中t1就发生了幻读,因为 t1读取的数据状态与后面的动作发生了语义上的冲突:查询的时候明明提示记录不存在,插入的时候去提示主键重复,类似于出现幻影,因而称之为幻读。
如何消除幻读
mysql当前有两种方式可以消除幻读:
1. 通过对select操作手动加行x锁(select ... for update )。原因是innodb中行锁锁定的
是索引,纵然当前记录不存在,当前事务也会获得一把记录锁(记录存在就加行x锁,不
存在就加next-key lock间隙x锁),这样其他事务则无法插入此索引的记录,杜绝幻
读。
2. 进一步提升隔离级别为serializable
测试一下效果
|
mysql> begin ; mysql> select * from user where id = 2 for update ; mysql> insert into user values (2, 'tony' ); mysql> commit ; |
t2:
|
mysql> begin ; mysql> insert into user values (2, 'jimmy' ); error 1062 (23000): duplicate entry '2' for key 'primary' |
现在t1查询时携带了for update,在innodb内会对该索引加锁(即使当前不存在),于是事务t2的insert会被阻塞直到t1显示提交,这样t1成功了,对于t1来说,幻读确实被消除了,但t2的插入会报主键重复,这也符合预期。
至于另外一种提升隔离级别消除幻读的方式感兴趣的可以自己尝试,这里不再重复,其本质是类似的,只是让系统代替了手工加锁。
总结
rr作为 mysql 事务默认隔离级别,是事务安全与性能的折中,正确认识幻读后,开发者便可以根据需求自行决定是否需要防止幻读。
serializable则是悲观的认为幻读时刻都会发生,故会自动的隐式的对事务所需资源加排它锁,其他事务访问此资源会被阻塞等待,故事务是安全的,但需要认真考虑性能。
innodb的锁是针对索引,这点需要引起注意。对行记录加锁,如果存在,加x锁,否则会加 next-key lock / gap 锁 / 间隙锁,故innodb可以实现事务对某记录的预先占用,只要本事务还在,其他事务就别想占有它。关于锁,后面还会再有专门的文章讨论。
以上就是详解mysql 幻读及如何消除的详细内容,更多关于mysql 幻读及消除的资料请关注开心学习网其它相关文章!
原文链接:https://zhuanlan.zhihu.com/p/360254683
- mysql账户访问权限(MySQL 权限控制详解)
- mysqljson字段查询(Mysql 查询JSON结果的相关函数汇总)
- mysql日志功能介绍(mysql日志系统的简单使用教程)
- mysql按端口查找配置(MySQL中给定父行找到所有子行的解决方案)
- mysql 8.0.22 winx64安装配置图文教程(mysql 8.0.22 winx64安装配置图文教程)
- mysql并发查询优化(详解MySQL 联合查询优化机制)
- mysql查看慢查询(MySQL 慢查询日志深入理解)
- python在mysql创建数据库(python3对接mysql数据库实例详解)
- phpstudymysql数据库启动不了(phpstudy mysql启动不了的解决方法)
- 创建数据库入门教程mysql(MySQL数据库安装教程一学就会)
- navicat15激活页面不显示(Navicat for MySQL 15注册激活详细教程)
- docker进入mysql查看路径(Docker 环境运行 Mysql 和开启 Binlog 配置主从同步的设置方法)
- mysqlworkbench怎么设置连接(详解MySQL Workbench使用教程)
- mysql查看死锁记录(mysql查看死锁与去除死锁示例详解)
- netcore连什么数据库好(.Net Core导入千万级数据至Mysql的步骤)
- mysql存储过程声明(MySQL存储过程的深入讲解in、out、inout)
- 新一小兰领衔 盘点动漫中的那些 远距离恋爱情侣(盘点动漫中的那些)
- 大事件 合肥四中火了(大事件合肥四中火了)
- 翼龙贷组织出借人调研 感受鄱阳 借 来的致富路(翼龙贷组织出借人调研)
- 2023新国风戏曲教育寒假集训班汇报演出《戏娃闹元宵》图文报道(2023新国风戏曲教育寒假集训班汇报演出戏娃闹元宵图文报道)
- 九儿《狐踪谍影》出演热血女特警,戏份杀青受关注(九儿狐踪谍影出演热血女特警)
- 红色代表什么(红色代表什么寓意)
热门推荐
- laravel 权限管理(laravel框架 laravel-admin上传图片到oss的方法)
- vue导出动态的excel功能(vue中如何下载excel流文件及设置下载文件名)
- idea 远程部署docker(通过idea打包项目到docker的操作方法)
- php系统转换的三种方式(PHP容器类的两种实现方式示例)
- python把str转成list(python3 字符串/列表/元组str/list/tuple相互转换方法及join函数的使用)
- python怎么测试api接口(python接口自动化测试之接口数据依赖的实现方法)
- vs项目依赖项
- 为什么网页不显示css效果(网页布局中CSS样式无效的十个重要原因详解)
- docker 加入k8s吗(k8s和Docker关系简单说明)
- Web.config 图形化编辑器:ASPhere
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9