大白话讲解脏写、脏读、可重复读和幻读
前言
当多个事务并发执行的时候,会导致什么问题?
我们知道,执行sql是在buffer pool中对数据进行查询或者修改。如若多个事务同时更新一行数据会出现什么问题?
1. 脏写
当事务A和事务B同时去更新同一行数据时,事务A先更新,事务B后更新。
图 1-1那么此时,undo log就会记录了事务A所改数据的旧值,假设旧值为 null。随后事务B也对该行数据进行了更新,覆盖掉A更新的值。此时事务A突然发生回滚,那么就会根据它的undo log进行回滚。
事务A进行了回滚,那么该数据的值就变成了更新前的null值。
图1-2然而,事务B并不知道此事,发现自己更新的值没有了。这就是 脏写
。
本质上,就是一个事务修改了另外一个没提交的事务的值(没提交有可能回滚),而导致有可能数据前后不一致的问题。
2. 脏读
同样有事务A和事务B。事务A去更新了一行数据,事务B刚好查询到了该行数据,此时事务B拿到的值为A更新的值。
图 2-1事务B拿到值后便去业务系统进行各种业务逻辑处理等等,这时,事务A突然回滚了,又把undo log的值回滚到该行数据。紧接着事务B再次查询该行数据的时候,发现前后的值不一样。这就是脏读
。
本质上,就是一个事务查询到了另个一个未提交的事务的值,而导致有可能数据前后不一致的问题。
3. 不可重复读
在避免脏读的前提下,还有可能出现的不可重复读
。
这类情况是在什么场景下发生的呢?
假设,有一个前提,事务B在更新某行数据,但暂未提交,在未提交事务的时间里,事务A是读不到该行数据的。必须等事务B提交了,事务A才能读取到它修改的值。这样就可以避免脏读。
这时,假设事务A第一次查询到的值为A值。
图 3-1事务B把该行数据的值改为B值并立即提交事务。而事务A尚未提交事务,在事务执行期间进行第二次查询,所以事务A第二次查询到的值为B值。
图 3-2紧接着事务C再次更新数据为C值,并提交了事务。此时,事务A在未提交事务的情况下,进行第三次查询,查到的值为C。
图 3-3不可重复读就是以上这种情况,事务A未提交事务,每次读到的数据可能都不一样。
通过以上分析,那可重复读,就很好理解了。即希望,事务A每次读到的值都是A值。
4. 幻读
假设事务A需要多次批量查询数据,第一次查询到了十条数据
图 4-1此时事务B往表里插入了几条数据,且B提交了事务,那么此时,就会多出几行数据
图 4-2接着事务A再次进行查询时,由于事务B的提交,导致事务A查询多出来了几条数据
图 4-3这样就出现了和查询第一次没见到的数据,就是幻读
。
本质上,就是一个事务用一样的sql进行多次查询,每次查询到没见过的数据。