REPEATABLE READ避免了不可重复读问题,事务内对同一数据的多次读取都是一致的。
一个事务修改一条数据,其他事务修改同一数据就要等待。
增、删数据时会出现幻读。
不可重复读的重点是修改数据,幻读的重点是增删数据。
事务各自COMMIT后,再查询,各自的修改内容就汇总在一起了。
2. 幻读(Phantom Read)
在Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题。
幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。
3. 例子
我们仍然先准备好students
表的数据:
mysql> select * from students;
+----+-------+
| id | name |
+----+-------+
| 1 | Alice |
+----+-------+
1 row in set (0.00 sec)
然后,分别开启两个MySQL客户端连接,按顺序依次执行事务A和事务B:
时刻事务A事务B1// 设置隔离等级
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;2BEGIN;BEGIN;3// 查询没有
SELECT * FROM students WHERE id = 99;
4// 插入一条数据Bob
INSERT INTO students (id, name) VALUES (99, 'Bob');
5COMMIT; 6// 再次查询也没有
// 因为Repeatable Read下在同一个事务内的查询都是与事务开始时刻一致,所以在B事务过程中是不会读到期间A中insert的值的
// REPEATABLE READ避免了不可重复读问题,事务内对同一数据的多次读取都是一致的。
SELECT * FROM students WHERE id = 99;
7// 更新成功
UPDATE students SET name = 'Alice' WHERE id = 99;
8// 再次读取,记录就有了
SELECT * FROM students WHERE id = 99;
9 COMMIT;事务B在第3步第一次读取id=99
的记录时,读到的记录为空,说明不存在id=99
的记录。
随后,事务A在第4步插入了一条id=99
的记录并提交。
事务B在第6步再次读取id=99
的记录时,读到的记录仍然为空,但是,事务B在第7步试图更新这条不存在的记录时,竟然成功了,并且,事务B在第8步再次读取id=99
的记录时,记录出现了。
可见,幻读就是没有读到的记录,以为不存在,但其实是可以更新成功的,并且,更新成功后,再次读取,就出现了。
4. 总结
- 脏读:读到别的事务没有提交的数据。
- 不可重复读:先前读取的数据,被别的事务改变了,再读就跟原来不一样了。
- 幻读:第一次读的时候发现什么都没有,另一个事务偷偷放了东西进去,执行更新操作,再去访问的时候,发现有变化,惊讶地居然发现有东西了。
https://www.liaoxuefeng.com/wiki/1177760294764384/1245268672511968