Mysql快速理解脏读、不可重复读、幻读
【数据库】快速理解脏读、不可重复读、幻读
理解这三种由于并发访问导致的数据读取问题,再理解事务隔离级别就简单多了。
【1】脏读(读取提交但未持久化/未提交的数据)
情况一:A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据。就好像原本的数据比较干净、纯粹,此时由于B事务更改了它,这个数据变得不再纯粹。这个时候A事务立即读取了这个脏数据,但事务B良心发现,又用回滚把数据恢复成原来干净、纯粹的样子,而事务A却什么都不知道,最终结果就是事务A读取了此次的脏数据,称为脏读。
情况二:A事务读取B事务提交了但是为持久化到磁盘的数据,因为提交后的数据到内存,各个线程为共享内存中的数据的,阔以读取到,但是数据只是存在于内存中,这时候发生回滚操作,则A读取到的数据为脏数据,称为脏读。
这种情况常发生于转账与取款操作中
时间顺序 | 转账事务 | 取款事务 |
---|---|---|
1 | 开始事务 | |
2 | 开始事务 | |
3 | 查询余额为两万元 | |
4 | 取款一万元,余额别更改为一万元 | |
5 | 查询账户余额为一万元 | |
6 | 取款操作发生未知错误,事务回滚,余额变为两万元 | |
7 | 转入两万元,余额被个改为了三万元(脏读的一万+两万) | |
8 | 提交事务 | |
9 | 提交事务 | |
10 | 按照正常的逻辑,此时的账户应该为四万元 |
【2】不可重复读(前后多次读取,数据内容不一致)
事务A在执行读取操作,由整个事务A比较大,前后读取同一条数据需要经历很长的时间 。而在事务A第一次读取数据,比如此时读取了小明的年龄为20岁,事务B执行更改操作,将小明的年龄更改为30岁,此时事务A第二次读取到小明的年龄时,发现其年龄是30岁,和之前的数据不一样了,也就是数据不重复了,系统不可以读取到重复的数据,成为不可重复读。
时间顺序 | 事务A | 事务B |
---|---|---|
1 | 开始事务 | |
2 | 第一次查询,小明的年龄为20岁 | |
3 | 开始事务 | |
4 | 其他操作 | |
5 | 更改小明的年龄为30岁 | |
6 | 提交事务 | |
7 | 第二次查询,小明的年龄为30岁 | |
8 | 提交事务 | |
9 | 按照正常的逻辑,事务A前后两次读取到的数据应该一致 |
【3】幻读(前后多次读取,数据总量不一致)
事务A在执行读取操作,需要两次统计数据的总量,前一次查询数据总量后,此时事务B执行了新增数据的操作并提交后,这个时候事务A读取的数据总量和之前统计的不一样,就像产生了幻觉一样,平白无故的多了几条数据,成为幻读。
时间顺序 | 事务A | 事务B |
---|---|---|
1 | 开始事务 | |
2 | 第一次查询,限定的条件下,数据的总量为100条 | |
3 | 开始事务 | |
4 | 其他操作 | |
5 | 新增数据的总量为100条 [ , 事务A限定的条件下] | |
6 | 提交事务 | |
7 | 第二次查询,限定的条件下,数据的总量为200条 | |
8 | 提交事务 | |
9 | 按照正常的逻辑,事务A前后两次读取到的数据量应该一致 |
【4】不可重复读 和 脏读的区别:
不可重复读的重点在修改,在同一事务中,同样的条件,第一次读取的数据和第二次读取的数据不一样(因为中间有其他事务提交了修改操作)
幻读的重点在插入,在同一事务中,同样的条件,第一次读取的记录数第二次读取的记录数不一致(因为中间有其他事务提交了插入操作)
我看有的文章说了幻读的重点在于插入和删除,其实不准确,幻读的重点只能在插入:
原因一:MySQL数据库的引擎为 InnoDB,而 InnoDB 的默认锁机制为行级锁,当事务A去查看限定条件下的数据时,那这些被查询的数据行则被上锁了,删除不了。
原因二:在相同的限定条件下,事务B去增加符合限定条件的数据,这个时候则会事务A再次读去相同限定条件的数据,则发生幻读,读取不相同的限定条件的数据,发生数据量不一致,这个原则上不称为幻读
幻读的解决办法:将锁级别改为表级锁,事务A操作时,直接将表上锁,其他事务操作不了,但这样效率大大降低。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!