在一个事务中查询多次会出现不一样数目的结果集。
结论在快照读情况下,可重复读可以避免幻读(MVCC)
在当前读情况下,可重复读还是会出现幻读。
当前读和快照读是针对某一行记录来说的。一个范围查询中当前读和快照读可以同时存在的
解释 快照读快照读又叫一致性读,读取的是快照数据。不加锁的简单的 SELECt 都属于快照读,即不加锁的非阻塞读;普通的select *。。。。
当前读当前读读取的是记录的最新版本(最新数据,而不是历史版本的数据),读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。加锁的 SELECT,或者对数据进行增删改都会进行当前
读。比如:
SELECT * FROM student LOCK IN SHARE MODE; # 共享锁 SELECt * FROM student FOR UPDATe; # 排他锁 INSERT INTO student values ... # 排他锁 DELETE FROM student WHERe ... # 排他锁 UPDATe student SET ... # 排他锁MVCC
MVCC (Multiversion Concurrency Control),多版本并发控制。顾名思义,MVCC 是通过数据行的多个版本管理来实现数据库的 并发控制 。这项技术使得在InnoDB的事务隔离级别下执行 一致性读 操作有了保证。
可重复读隔离级别下的快照读,一个事务中查询语句会产生一个快照ReadView。然后每次查询都查不到之后新增或者修改的数据。
CREATE TABLE `course` ( `id` int(11) NOT NULL AUTO_INCREMENT, `course_id` int(11) NOT NULL, `course_name` varchar(40) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=217 DEFAULT CHARSET=utf8;事务演示
| 时刻 | 事务1 | 事务2 | 事务1结果 |
|---|---|---|---|
| t1 | BEGIN; | 没开始 | 无 |
| t2 | select * FROM course; | BEGIN; | 查询出1条数据 |
| t3 | select * FROM course; | INSERT INTO course (course_id,course_name) values(6,‘事务2’); | 查询出1条数据 |
| t4 | COMMIT; | 无 | |
| t5 | select * FROM course; | 查询出1条数据 | |
| t6 | UPDATe course set course_name=‘sqqs’ where course_id =6 | 修改影响1行 | |
| t7 | select * FROM course; | 查询出2条数据 |
事务1在【t5】时刻查询还是一条数据,证明在可重复读下快照读不会出现幻读。
事务1在【t6】时刻进行了修改操作使得【course_id=6】(事务2在t4时刻提交的数据)变成了当前读。所以在【t7】时刻再读取时就读取到了course_id=6的数据。
在t1-t2同一个事务下查询,这里是选择执行了,如下图。
结果还是一条数据,没有出现幻读。
事务1执行了修改操作使得course_id=6的数据变成了当前读。
因为t6时刻把course_id=6变成了当前读导致读取最新数据,所以出现了两条数据,造成了幻读现象。
不能认为可重复读就一定会出现幻读问题,必须要上串行化级别才能解决幻读问题。
在快照读情况下,可重复读可以避免幻读(MVCC)
在当前读情况下,可重复读还是会出现幻读,要串行化级别才能解决。



