mysql 事务 Repeatable Read

在这之前介绍了mysql隔离级别最低的一种事务级别 Read Uncommitted,还介绍了可能出现不可重复读(Non Repeatable Read)的事务隔离级别 Read Committed,今天介绍一下相对更高的mysql事务隔离级别Repeatable Read。

在Repeatable Read隔离级别下,一个事务可能会遇到幻读(Phantom Read)的问题。

幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。

我们来测试一下,首先准备一个有数据的student表:

然后,分别开启两个MySQL客户端连接,按顺序依次执行事务A和事务B:

时刻 事务A 事务B
1 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
2 BEGIN; BEGIN;
3 SELECT * FROM student WHERE id = 4;
4 INSERT INTO student (id, name) VALUES (4, '张三');
5 COMMIT;
6 SELECT * FROM student WHERE id = 4;
7 UPDATE student SET name = '李四' WHERE id = 4;
8 SELECT * FROM student WHERE id = 4;
9 COMMIT;

 事务B在第3步第一次读取id=4的记录时,读到的记录为空,说明不存在id=4的记录。随后,事务A在第4步插入了一条id=4的记录并提交。事务B在第6步再次读取id=4的记录时,读到的记录仍然为空,但是,事务B在第7步试图更新这条不存在的记录时,竟然成功了,并且,事务B在第8步再次读取id=4的记录时,记录出现了。

可见,幻读就是没有读到的记录,以为不存在,但其实是可以更新成功的,并且,更新成功后,再次读取,就出现了。

  比起Read UncommittedRead Committed ,Repeatable Read隔离级别相对较高,不会出现 脏读和不可重复读的情况,但是会出现幻读的情况。

总结一下就是:

  • 脏读:读到别的事务没有提交的数据。
  • 不可重复读:先前读取的数据,被别的事务改变了,再读就跟原来不一样了。
  • 幻读:一个事务插入了某条数据,另一个事务去读插入的那条数据的时候发现没有,更新这条记录的时候又成功了,再次查询这条记录就出现了。

脏读是因为在读是时候没有加共享锁,不可重复读是因为没有遵循两阶段加锁,即在释放锁之后不能申请锁,所有锁的申请必须在释放之前。幻读可能是因为锁的颗粒度问题。如果是严格按照两阶段锁的模型,即使读取不存在的元素,也要将该元素上锁,如果是这样的话,那insert语句会失败,也就不会有幻读的问题。

猜你喜欢

转载自blog.csdn.net/lwpoor123/article/details/126765647