Innodb事务--隔离级别

2021-07-02  本文已影响0人  账号已被冻结

innodb 事务有四个隔离级别,分别为:未提交读、提交读、重复读与序列化

由于隔离级别的不同,会导致如下问题:脏读、不可重复读、幻读。

脏读:指当前事务能看到其他事务还没Commit的内容。

不可重复读:同一个事务中,分别两次查询相同的一行数据,看到的结果不一致。

幻读:幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。

不可重复读和幻读最大区别:不可重复读重点在于update和delete,而幻读的重点在于insert,也有说法是幻读 侧重行发生了变化;不可重复读侧重某行数据的修改。不可重复读是修改了存在的数据,导致两次查看不一致,幻读是新增了之前不存在的数据。

下面一一解释各个隔离级别会产生的问题与如何解决脏读、不可重复读、幻读

未提交读

事务中的修改,即使没有提交,其他事务也可以看得到,会导致“脏读”、“幻读”和“不可重复读取”

提交读(RC)

一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”,但不能避免“幻读”和“不可重复读取”。

为什么无不能避免幻读和不可重复读?
因为每次读取都会重新生成一个快照,所以每次快照都是最新的,也因此事务中每次SELECT也可以看到其它已commit事务所作的更改;

可重复读(RR)

这是MySQL中InnoDB默认的隔离级别。从读的角度看, 快照会在事务中第一次SELECT语句执行时生成,只有在本事务中对数据进行更改才会更新快照

RR级别的事务隔离可以解决脏读和不可重复读,他通过MVVC解决了快照读情况下的幻读问题,当前读下的幻读是以来Innodb的锁机制实现的。所以总结起来就是:
1.在快照读情况下,Mysql通过MVVC来避免幻读。
2.在当前读的情况下,Mysql通过锁机制来避免幻读。

可以通过下面SQL进行测试

事务1: begin; select * from ab; // empty set 

事务2: begin; insert into ab values(1,1); 

       commit; 

事务1: select * from ab; // empty set

      update ab set b = 2 where a = 1; // 1 row affected. 

      select * from ab; // 1 row

上述例子,事务2插入语句并且提交了,事务1通过update语句能更新到,那是因为update语句是当前都,他能读到现在最新的数据并加锁。下面语句要达到可重复度的级别,需要这样修改:

事务1: begin; select * from ab for update; // empty set 

事务2: begin; insert into ab values(1,1);  //block,事务1当前读已经加了锁

事务1: select * from ab; // empty set

      update ab set b = 2 where a = 1; // 1 row affected. 

      select * from ab; // 1 row

所以,网上很多说可重复读通过MVVC机制解决了幻读问题,其实是不正确的,锁机制才是解决可重复读下幻读问题的重大功臣

当前读与快照读

这里补充说明下当前读与快照读是什么!

快照读:读取专门的快照 (对于RC,快照(ReadView)会在每个语句中创建。对于RR,快照是在事务启动时创建的)。简单的select操作即可。

当前读:读取最新版本的记录, 没有快照。 在InnoDB中,当前读取根本不会创建任何快照。语句包括:select ... lock in share mode、select ... for update、inset、update、delete。当前读是通过手动加record lock(记录锁)和gap lock(间隙锁)来实现的。

待续-后续讲下事务的原理

上一篇下一篇

猜你喜欢

热点阅读