关于Mysql中快照读幻读问题一点思考

1、前言

因为本身对于Mysql的事务隔离级别解决了什么问题,它的原理是什么,使用了什么机制等都理解得比较模糊。就我目前的认知水平我姑且先总结几点个人理解,以便于后面被颠覆,刷新本身的认知,从中取得进步。sql

  1. 读未提交:未加任何锁也没有使用MVCC机制。当前事务内能够读取别的事务未提交的变动,从而引起脏读、不可重复读、幻读等问题。
  2. 读已提交:读(select)操做不加锁,同时使用MVCC机制,写操做加行锁。只会读到小于等于当前事务版本号的记录,解决了脏读的问题,可是可重复读、幻读依然存在。
  3. 可重复读:读(select)操做不加锁,同时使用MVCC机制,写操做加行锁、间隙锁。因为MVCC机制和间隙锁的存在,解决了快照读的可重复读问题而且部分解决了快照读的幻读问题。依然存在个别状况下快照读幻读问题及当前读的幻读问题。

2、实验

针对于Mysql的默认隔离级别(可重复读)下,为何说部分解决了快照读的幻读问题呢?请看如下示例。并发

场景一

一、事务Aapp

BEGIN;
SELECT * FROM product_brand_info WHERE brand_id >= 0;
SELECT * FROM product_brand_info WHERE brand_id >= 0;
COMMIT;

二、事务Bspa

BEGIN;
SELECT * FROM product_brand_info WHERE brand_id >= 0;
INSERT INTO `product_db`.`product_brand_info`(`brand_name`, `telephone`, `brand_status`, `brand_order`, `modified_time`) VALUES ('kappa', '', 1, 0, NOW());
COMMIT;

三、说明
brand_id为品牌表的自增id,以上两个事务A、B并发执行,不管事务B是否提交事务,事务A中的查询语句结果集里面都不会出现事务B新增的记录。这么看来Mysql的默认事务隔离级别(可重复读)已经解决了幻读的问题,事实果然如此吗?请接着看下一个场景。3d

场景二

一、事务Acode

BEGIN;
#1
SELECT * FROM product_brand_info WHERE brand_id >= 36;
#4
UPDATE `product_db`.`product_brand_info` SET `brand_name` = '鸿星尔克增强版' WHERE `brand_id` >=36;
#5
SELECT * FROM product_brand_info WHERE brand_id >= 36;
#6
COMMIT;

二、事务Bblog

BEGIN;
#2
INSERT INTO `product_db`.`product_brand_info`(`brand_name`, `telephone`, `brand_status`, `brand_order`, `modified_time`) VALUES ('kappa', '', 1, 0, NOW());
#3
COMMIT;

三、标号执行结果事务

  • 事务A操做一执行结果

image.png

  • 事务B操做二新增一条品牌记录
  • 事务B操做三提交事务
  • 事务A操做四执行条件更新操做

image.png

  • 事务A操做五查询操做

image.png

  • 事务A操做六提交

四、说明
主要注意事务A的操做四及操做五,操做四的更新操做影响了两条记录,此更新操做当前读读到了事务B的最新提交的数据并对其进行了更新,事务A的操做五查询返回的结果集也返回了事务B插入的记录。it

3、结论

根据以上实验过程,加入自我思考及猜测。在Mysql默认的事务级别下,确实部分解决了快照读的幻读问题,这正是场景一所说明的问题,这得益于MVCC机制;可是它也仅仅是部分解决,场景二举了反例说明,当前读能读到最新的事务提交结果,而且更新掉记录的建立版本号为当前事务版本号,因此当前事务内的查询有可能会查询到别的已提交事务新增的记录,出现幻读现象。class

相关文章
相关标签/搜索