转载 

细说一下事务隔离机制是怎么解决脏写、脏读、不可重复读和幻读的

分类:    225人阅读    IT小君  2023-08-19 14:01
图片

我们已经知道了,MySQL 是支持多个事务并发执行的。有的事务写、有的事务读,这种读写冲突是有可能发生脏写、脏读、不可重复读和幻读问题的。具体可以参考这篇文章:图解脏写、脏读、不可重复读、幻读

MySQL 正是用事务隔离机制来解决这些问题的。简单来说,事务的隔离就是对事务的读操作做了一些限制,根据限制的严格程度分成了 4 个事务隔离级别:read uncommitted(读未提交),read committed(读已提交),repeatable read(可重复读),serializable(串行化)这几个隔离级别。

本文会比较轻松,目的是介绍这 4 种隔离机制的基本原理,为后面介绍隔离机制的底层原理打下基础。



如何避免脏写、脏读?


我们再次回过头看脏写和脏读。它们产生的原因可以归纳为,事务 A 读到了未提交的事务,而未提交的事务是可以回滚的。

回滚就会导致,事务 A 正确读取到了某个值,这个值也会随着别的事务回滚,又变成另一个值了。

这种时候,我们采用的隔离级别就被称为:read uncommitted(读未提交),表示事务可以读到别的事务还没有提交的事务。

图片

所以解决脏写、脏读问题的方法就很简单,不允许一个事务读取还没有提交的事务。从隔离级别的角度来理解,就是将隔离级别,从 read uncommitted(读未提交),提高到 read committed(读已提交)

在读已提交这个隔离级别下,事务只能读到已经提交的事务,也就避免了事务回滚带来的脏写、脏读问题。

如何避免不可重复读?


不可重复读是指:在读已提交这样的隔离级别下

  • 一个事务 A 读某一行数据,第一次读到某个值,比如说是 x;

  • 该事务第二次读同一行数据,读到的值变成 y 了。


为什么值会变成 y 了呢?其实很容易理解,因为读已提交意味着,只要事务修改了数据,并且提交了,那就可以被别的事务读到。

那么上面的读取的流程实际上是这样的:

  • 一个事务 A 读某一行数据,第一次读到某个值,比如说是 x;

  • 事务 B 对该行数据做了一个修改操作,改成了 y,并提交了事务;

  • 在读已提交的隔离级别下,事务 A 就可以读到这个被修改的值 y。


那这里其实还有一个问题值得被考虑,读已提交这个隔离级别有什么问题么?或者说,不可重复读有什么问题么?我执行事务,读取到值虽然不同,但都是已经提交的事务所修改的值。

其实仔细想来不可重复读也不能说它有问题,只能说不符合一些场景下我们的预期而已。比如我们预期的是一个事务第一次读一个值是 x,后面再读永远都是 x,不会改变。

怎么做到可重复读呢?那就可以将隔离级别从 read committed(读已提交)提升到 repeatable read(可重复读)

在可重复读这个隔离级别下,它会在事务开启的时候,把值都记下来,以后读的时候,就读原来记下来的值就可以了。就像我们写代码的时候。

具体它是怎么把值记录下来的,又是怎么读的,会在下一篇文章详细描述。

如何解决幻读?


可重复读这个隔离级别下,还是有可能产生幻读问题的。因为执行 select * from user where id > 11; 这样一个 SQL,第一次查询到 20 条数据,接着别的事务可能插入了新的数据,下次查询就可能查到 21 条。

解决幻读的方法就是将隔离级别提高到 serializable(串行化),这也是最高的隔离级别。它一次只能执行一个事务,完全禁止并发,大家排好队一个个执行,就啥事儿都没有喽。但实际开发中是不会有人用这个隔离级别的。



转载于:http://mp.weixin.qq.com/s?__biz=MzI5MzQ2MDg4Nw==&mid=2247483818&idx=1&sn=b31bc2da388d514c8ecf41dfee4ad2f3&chksm=ec708f52db0706441907b7be850b1edf1dcadb437c33f3c727737afc6191bb19f26e63e1e456#rd

支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者

 工具推荐 更多»