什么是 脏写,脏读,幻读,不可重复读?如何解决?
目录1. 脏写2. 脏读3. 不可重复读4. 幻读5. 四种隔离级别我们通过如下语句先创建一个 student 学生表。我就以对学生表的操作来解释什么是脏写脏读幻读不可重复读创建完成之后随便插入一条数据1. 脏写对于两个事务 SessionASessionB如果SessionB修改了SessionA已经提交的数据数据库中存储的数据与SessionA执行过后的预期数据不符合这种现象我们称为脏写。过程如下图所示假设我们对刚才的 student 学生表做一些操作SessionA事务修改学号为1的姓名为张三SessionB事务修改学号为1的姓名为李四。第一步SessionA开始了修改姓名这个事务操作第二步SessionB也开始了修改姓名这个事务操作第三步SessionB完成了修改姓名这一步操作并在内存中进行了提交但未保存至磁盘第四步SessionA完成了修改姓名这一步操作并在内存中进行了提交也未保存至磁盘第五步SessionA准备将数据写入磁盘进行持久化保存第六步SessionB事务中途出现了一些状况事务回滚因为SessionA是在SessionB之后修改的姓名SessionB回滚就会将SessionA所写的数据张三回滚成原来的小谷这样的话表面看来SessionA顺利进行实际上由于SessionB的回滚操作导致我们SessionA的写操作根本没有成功但我们得到的却会是SessionA事务执行成功这种现象就是脏写。2. 脏读对于两个事务SessionASessionB。SessionA读取了SessionB更新了但未提交的数据之后若SessionB进行了回滚那么SessionA读取到的数据就是临时而且无效的数据这种现象称为脏读。过程如下图所示假设事务SessionA要查询学号为1的学生信息事务SessionB要修改学号为1的学生信息。第一步SessionA开始事务操作第二步SessionB也开始事务操作第三步SessionB修改了学号为1的学生信息并在内存进行了暂时提交未保存到磁盘第四步SessionA查询学号为1的学生信息查询到的是SessionB刚刚修改过的信息第五步SessionA查询之后返回数据并提交事务第六步SessionB再提交的过程中出现错误事务回滚因为SessionB进行了回滚那么SessionB所作的修改都会被撤回更新操作未成功但是我们的SessionA中读取到的是SessionB暂时更新后的数据此时查询到的数据与保存在数据库中的真实数据不相同这种情况就称为脏读。3. 不可重复读两个事务 显式SessionA隐式事务SessionB。(这里说一下显式事务需要手动开启和提交而隐式事务会自动开启和提交)SessionA从数据库读取到了一条数据SessionB更新SessionA读取的那条数据并提交此时SessionA事务再次进行查询该数据发现这一次查询的结果与上一次不同两者不一致这种现象被称为不可重复读。过程如下图所示第一步SessionA开始事务第二步SessionA查询学号为1的学生信息查询到王五第三步SessionB修改了学号为1的学生姓名第四步SessionA再次查询发现查询到的是SessionB修改后的张三与刚才读到的数据王五不一致后面第五第六步是再次修改和查询。因为SessionA在查询到王五之后可能去执行其他SQL语句了。然后SessionB对其作了修改SessionA再次查询数据发现数据不一致这种情况称为不可重复读。这里注意不可重复读重点关注的是每一行的数据是否一致不过分关注读取到的数据量是否相同数据量的变换归结为幻读。4. 幻读两个事务 SessionASessionB。SessionA从一个表中读取到了某些字段的值然后SessionB在表中添加了一些新的数据SessionA再次去读的时候发现多了一些数据这种现象称为幻读。过程如下图所示第一步SessionA开启事务第二步SessionA查询数据之查询到了一条满足条件的数据张三第三步SessionB向表中添加了一些新的数据第四步SessionA再次查询数据发现满足条件的数据变多了像产生了幻觉一样这种情况就是幻读。还有一种情况就是SessionB执行的是删除操作当SessionA再次查询时发现少了一些记录也可以称作幻读。幻读主要关注读取到的数据量是否与之前一致这一点与刚才的不可重复读略有区别。5. 四种隔离级别上面我们提到了脏写脏读不可重复读幻读四种可能发生的并发问题它们的严重程度也是有先后之分的在我们看来他们的严重程度是 脏写 脏读 不可重复度 幻读。在我们的理想状态下当然是希望将上面的四个问题全部解决但是这样做会导致我们数据库并发能力非常弱这对于我们业务高并发是不兼容的因此在实际开发过程中我们通常会设置一些隔离级别这些隔离级别越低并发问题发生的就越多但同时并发能力越高。SQL 标准中一共设立了四种隔离级别。READ UNCOMMITTED读未提交在这种隔离级别下我们的事务可以读取到其他事务还没有提交的数据。不能避免脏读不可重复读幻读。READ COMMITTED读已提交它满足了事务的简单特性一个事务只能看到一个已经提交事务所作出的改变可以避免不可重复读幻读。REPEATABLE READ可重复读当事务A读取到一条数据时若事务B对该数据做了修改事务A再次查询此数据查询到的还是原来未修改的数据解决了不可重复读脏写脏读的问题。可重复度是 InndDB 存储引擎的默认隔离级别。SERIALIZABLE可串行化确保一个事务可以从一个表中读取相同的行在这个事务持续期间其他事务不能对该表进行插入修改删除操作所有的并发问题都得到了解决但是效率确实非常的低。上述四种隔离级别都解决了脏写的问题因为脏写问题是最为严重的所以上述四种隔离级别都解决了脏写问题大致可以总结为以下一张图表其实通过上面的介绍同学们应该也能看出来一个特点数据库的隔离程度越高并发效率越低数据库的隔离程度越低并发效率越高。有兴趣深入了解上述四种隔离级别实现原理的同学可以阅读我的另一篇文章数据库 MVCC 详解揭秘 MVCC 是如何解决脏写、脏读、不可重复读、幻读-CSDN博客