mysql幻读

首先,mysql 幻读并非是”一个事务内进行两次相同操作居然得到了不一样的结果”,因为它根本不可能发生在使用了 read view / MVCC 的 RR 隔离级别下,这种幻读的定义更适合给 Oracle,Oracle 的事务隔离只有两级,RC 和 Serializable。然后还有很多人辩解说不可重复读是针对某条记录的,幻读是针对记录集合的,这是在自我安慰么?

这里给出 mysql 幻读的比较形象的场景:

users: id 主键

1、T1:select * from users where id = 1;

2、T2:insert into `users`(`id`, `name`) values (1, ‘big cat‘);

3、T1:insert into `users`(`id`, `name`) values (1, ‘big cat‘);

T1 :主事务,检测表中是否有 id 为 1 的记录,没有则插入,这是我们期望的正常业务逻辑。

T2 :干扰事务,目的在于扰乱 T1 的正常的事务执行。

在 RR 隔离级别下,1、2 是会正常执行的,3 则会报错主键冲突,对于 T1 的业务来说是执行失败的,这里 T1 就是发生了幻读,因为T1读取的数据状态并不能支持他的下一步的业务,见鬼了一样。

在 Serializable 隔离级别下,1 执行时是会隐式的添加 gap 共享锁的,从而 2 会被阻塞,3 会正常执行,对于 T1 来说业务是正确的,成功的扼杀了扰乱业务的T2,对于T1来说他读取的状态是可以拿来支持业务的。

所以 mysql 的幻读并非什么读取两次返回结果集不同,而是事务在插入事先检测不存在的记录时,惊奇的发现这些数据已经存在了,之前的检测读获取到的数据如同鬼影一般。

这里要灵活的理解读取的意思,第一次select是读取,第二次的 insert 其实也属于隐式的读取,只不过是在 mysql 的机制中读取的,插入数据也是要先读取一下有没有主键冲突才能决定是否执行插入。

不可重复读侧重表达 读-读,幻读则是说 读-写,用写来证实读的是鬼影。

下面例子版本

SELECT VERSION();

例子1,读提交


a


b


SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;


SET AUTOCOMMIT=0;


1.不可重复读


begin


begin


INSERT test VALUES(1,1);


SELECT * FROM test;


SELECT * FROM test;


commit


SELECT * FROM test;

 


COMMIT


B在一个事务的查询的结果变了,不可重复读


2.锁


begin


begin


INSERT test VALUES(2,2);


SELECT * FROM test;


INSERT test VALUES(2,2);


Lock wait timeout exceeded; try restarting transaction


COMMIT


COMMIT


begin


INSERT test VALUES(3,3);


INSERT test VALUES(4,4);


COMMIT


BEGIN


BEGIN


SELECT COUNT(*) FROM test WHERE a>2;


SELECT COUNT(*) FROM test WHERE a>2;

   

INSERT test VALUES(5,5);


SELECT COUNT(*) FROM test WHERE a>2;


SELECT COUNT(*) FROM test WHERE a>2;

   

COMMIT


SELECT COUNT(*) FROM test WHERE a>2;


SELECT COUNT(*) FROM test WHERE a>2;

 

 

例子2:重复读


a


b


SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;


SET AUTOCOMMIT=0;


1.可重复读


begin


begin


INSERT test VALUES(1,1);


SELECT * FROM test;


SELECT * FROM test;


commit


SELECT * FROM test;

 


COMMIT


BEGIN


SELECT * FROM test;

 


COMMIT


B在一个事务的查询的没变


2锁


begin


begin


INSERT test VALUES(2,2);


SELECT * FROM test;


INSERT test VALUES(2,2);


Lock wait timeout exceeded; try restarting transaction


COMMIT


COMMIT


3(幻读)


BEGIN


BEGIN


INSERT test VALUES(3,3);


SELECT * FROM test;


SELECT * FROM test;


COMMIT


SELECT * FROM test;


INSERT test VALUES(3,3);


Duplicate entry ‘3‘ for key ‘PRIMARY‘


COMMIT


BEGIN


SELECT * FROM test;


COMMIT


幻读,b明明查到没有,插入时候提示主键冲突,刚刚查询没有,出现幻觉?


begin


INSERT test VALUES(4,4);


COMMIT


4.可重复读


BEGIN


BEGIN


SELECT COUNT(*) FROM test WHERE a>2;


SELECT COUNT(*) FROM test WHERE a>2;

   

INSERT test VALUES(5,5);


SELECT COUNT(*) FROM test WHERE a>2;


SELECT COUNT(*) FROM test WHERE a>2;

   

COMMIT


BEGIN


SELECT COUNT(*) FROM test WHERE a>2;


SELECT COUNT(*) FROM test WHERE a>2;

 

 


COMMIT


COMMIT

网上很多说范围啊,count等等都是不对的,不用于幻读

时间: 2024-10-12 22:50:19

mysql幻读的相关文章

mysql 幻读

幻读(Phantom Read) 是指当用户读取某一范围的数据行时,B事务在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影”行.InnoDB和Falcon存储引擎通 过多版本并发控制机制解决了幻读问题. http://bbs.csdn.net/topics/360050896 http://narcissusoyf.iteye.com/blog/1637309 http://hudeyong926.iteye.com/blog/1490687 http://imysql.c

一文带你理解脏读,幻读,不可重复读与mysql的锁,事务隔离机制

首先说一下数据库事务的四大特性 1 ACID 事务的四大特性是ACID(不是"酸"....) (1) A:原子性(Atomicity) 原子性指的是事务要么完全执行,要么完全不执行. (2) C:一致性(Consistency) 事务完成时,数据必须处于一致的状态.若事务执行途中出错,会回滚到之前的事务没有执行前的状态,这样数据就处于一致的状态.若事务出错后没有回滚,部分修改的内容写入到了数据库中,这时数据就是不一致的状态. (3) I:隔离性(Isolation) 同时处理多个事务时

Mysql事务,并发问题,锁机制-- 幻读、不可重复读(转)

1.什么是事务 事务是一条或多条数据库操作语句的组合,具备ACID,4个特点. 原子性:要不全部成功,要不全部撤销 隔离性:事务之间相互独立,互不干扰 一致性:数据库正确地改变状态后,数据库的一致性约束没有被破坏 持久性:事务的提交结果,将持久保存在数据库中 2.事务并发会产生什么问题 1)第一类丢失更新:在没有事务隔离的情况下,两个事务都同时更新一行数据,但是第二个事务却中途失败退出, 导致对数据的两个修改都失效了. 例如: 张三的工资为5000,事务A中获取工资为5000,事务B获取工资为5

mysql repeatable-read 一次利用间隙锁解决幻读案例

repeatable-read是Mysql默认事务隔离级别!能解决脏读以及不可重复读的问题,但可能出现幻读的情况 不可重复读:在一个未提交的事务里,二次查询结果可能不相同,因为在这个事务执行过程中,外面的   事务可能对这个数据集进行了修改并提交! 幻读:一个事务在操作过程中!有别的事务对此数据集进行了修改并提交,但这些操作第一个事务读不到,等到这个事务提交的时候,便有可能引起明明插入的数据没有查询到,但却出现插入重复的错误! 不可重复读与幻读的区别: 不可重复读是能读到其它事务已经提交的数据,

很经典的mysql的幻读解释

http://blog.sina.com.cn/s/blog_499740cb0100ugs7.html 上述链接很经典的解释了mysql的mvcc为什么是部分解决了幻读的问题. 同时我需要理解的是,在业务逻辑中,事务是可以分散在业务代码里面的,并不是说一条语句写出.比如,我们启动了一个事务,start transaction.先获取数据库中的数据,然后在业务中判断该条件是否符合自己的业务逻辑,如果是的话,那么就可以插入一部分数据.但是这个时候可能也有别的数据插入进来了,产生了冲突,导致当前的数

总是忘记的场景:MySQL InnoDB四个事务级别 与 脏读、不重复读、幻读

MySQL InnoDB事务隔离级别脏读.可重复读.幻读 MySQL InnoDB事务的隔离级别有四级,默认是“可重复读”(REPEATABLE READ). ·        未提交读(READUNCOMMITTED).另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据(脏读). ·        提交读(READCOMMITTED).本事务读取到的是最新的数据(其他事务提交后的).问题是,在同一个事务里,前后两次相同的SELECT会读到不同的结果(不重复读).

MySQL事务隔离级别为"REPEATABLE-READ"下的"幻读"现象

MySQL事务隔离级别为"REPEATABLE-READ"下的"幻读"现象 关于mysql命令行中事务控制的语句见该文章:http://my.oschina.net/xinxingegeya/blog/296459 本片参考文章:http://blog.csdn.net/jiao_fuyou/article/details/16368827 http://www.cnblogs.com/hancf/archive/2012/08/28/2660422.html my

MySQL InnoDB四个事务级别 与 脏读、不反复读、幻读

MySQL InnoDB事务隔离级别脏读.可反复读.幻读 希望通过本文.能够加深读者对ySQL InnoDB的四个事务隔离级别.以及脏读.不反复读.幻读的理解. MySQL InnoDB事务的隔离级别有四级,默认是"可反复读"(REPEATABLE READ). ·        未提交读(READUNCOMMITTED). 还有一个事务改动了数据,但尚未提交.而本事务中的SELECT会读到这些未被提交的数据(脏读). ·        提交读(READCOMMITTED).本事务读取

MySQL InnoDB四个事务级别 与 脏读、不重复读、幻读

MySQL InnoDB事务隔离级别脏读.可重复读.幻读 希望通过本文,可以加深读者对ySQL InnoDB的四个事务隔离级别,以及脏读.不重复读.幻读的理解. MySQL InnoDB事务的隔离级别有四级,默认是"可重复读"(REPEATABLE READ). ·        未提交读(READUNCOMMITTED).另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据(脏读). ·        提交读(READCOMMITTED).本事务读取到的