数据库难点:脏读幻读不可重复读与四种隔离级别

Posted 冰棍hfv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库难点:脏读幻读不可重复读与四种隔离级别相关的知识,希望对你有一定的参考价值。

目录

前言

本章着重点是介绍:出现脏读、幻读、不可重复读的原因,以及设定四种隔离级别如何解决这些现象,结合图例让读者阅读得更加通透


一、什么是事务?

所谓事务是用户定义的一个数据库序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。

在SQL中,定义事务的语句一般有三条:
BEGIN TRANSACTION;
COMMIT;
ROLLBACK;
事务通常是以BEGIN TRANSACTION开始,以COMMITROLLBACK结束。

  • COMMIT:表示提交,即提交事务的所有操作
  • ROLLBACK:表示回滚

二、事务的ACID特性

【重点】事务具有4个特性:原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持续性(Durability)。这4个特性简称为ACID特性

(1)原子性

事务是一个原子性质的操作单元,事务里面的对数据库的操作要么都执行,要么都不执行。

(2)一致性

在事务开始之前和完成之后,数据都必须保持一致状态,必须保证数据库的完整性。也就是说,数据必须符合数据库的规则。

(3)隔离性

一个事务的执行不能被其他事务干扰。即一个事务的内部操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能互相干扰。

(4)持久性

持久性也成为永久性,指一个事务一旦提交,它对数据库中数据的改变就应该是永久的。

三、何为脏读,幻读,不可重复读?

(1)脏读
脏读也俗称“读未提交”,顾名思义,就是某一事务A读取到了事务B未提交的数据,如图所示:

T2时刻,事务B把原来李华的年龄由原数据13改为了23,此后又被T3时刻的事务A读取到了,但是T4时刻事务B发生异常,进行了回滚操作。这个过程,我们称23为脏数据,事务A进行了一次脏读。

(2)不可重复读
不可重复读,有时候也会说成“读已提交”。什么意思呢,就是在一个事务内,多次读取同一个数据,却返回了不同的结果。实际上,这是因为在该事务间隔读取数据的期间,有其他事务对这段数据进行了修改,并且已经提交,就会发生不可重复读事故。

图示中事务A在T1和T4查询同一语句,却得到了不同的结果,这是因为T2~T3时刻事务B对该数据进行了修改,并提交。这个过程,出现了在一个事务内两次读到的数据却是不一样的,我们称为是不可重复读。

不可重复读和脏读的区别:前者是“读已提交”,后者是“读未提交”

(3)幻读
幻读是指当事务不独立执行时,插入或者删除另一个事务当前影响的数据而发生的一种类似幻觉的现象。举个例子,某事务在检查表中的数据数count时,是10,过一段时间之后再查是11,这就发生了幻读,之前的检测获取到的数据如同幻觉一样。

出现幻读和不可重复读的原因很像,都是在多次操作数据的时候发现结果和原来的不一样了,出现了其他事务干扰的现象。但是,幻读的偏重点是添加和删除数据,多次操作数据得到的记录数不一样;不可重复读的偏重点是修改数据,多次读取数据发现数据的值不一样了。 幻读图示如下:

事务B向表中新插入了一条数据,事务A在T3时刻后查询数据的时候,突然发现数据和以前查询的时候多出了一项,像产生了幻觉一样。

四、四种隔离级别

1.读未提交(Read Uncommitted):在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)


2.读已提交(Read Committed):这是大多数数据库系统的默认隔离级别(但不是mysql默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(NonrepeatableRead),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果


3.可重复读(Repeatable Read):这是MySQL的默认事务隔离级别,同一事务的多个实例在并发读取数据时,会看到同样的数据。不过理论上,这会导致另一个棘手的问题:幻读(Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。


4.可串行化(Serializable):这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争

这四种隔离级别越往后越影响性能,如何选取根据业务需求而定。以下是四种隔离级别中对脏读、不可重复读、幻读的影响情况。

  • 读未提交(Read Uncommitted)依旧存在脏读、不可重复读和幻读;
  • 读已提交(Read Committed)解决了脏读问题,因为发生脏读的条件就是读未提交的数据;
  • 可重复读(Repeatable Read)进一步解决了不可重复读的问题,从隔离名称就可以看出,但还存在幻读问题;
  • 可串行化(Serializable)解决了脏读、幻读、不可重复读问题,但是设立这种隔离级别会大大消耗性能。




参考文章:
https://blog.csdn.net/qq_41895699/article/details/106418547

数据库隔离 脏读 幻读与不可重复读

一、隔离级别与现象

数据库隔离有4个级别

read uncomitted ,未授权读取

read committed ,授权读取

repeatable read , 可重复读

serializable ,串行化

 

可能产生的不一致的现象有3种

脏读

不可重复读

幻读

 

二、3种现象

  脏读,就是读了脏数据;另一个事务修改了数据但未提交,我们读到了这个未提交的数据即脏数据,这种现象就是脏读;

举个栗子,balance字段值为100,另一个事务修改为200,未提交的时候我们读到了200,接着那个事务回滚了,实际值应该是100,但我们读的是200;

 

  不可重复读,就是对于一个数据,我重复读的时候它的值发生了改变;即两次读取之间被另一个事务进行了修改;

再举个栗子,我读到balance字段值为100,我做了判断(比如是否大于0),然后我再次读的时候它变成了200; 对于100这个值我没有重复读到,即发生了不可重复读;

 

  幻读,就是再次读取时发现了新的记录或少了记录,以为出现了幻觉;

最后一颗栗子,我读数据的时候没有balance字段,我要新增balance为0时,提示我存在这个字段了;我第二次读的时候 多了这条记录,我以为第一次读出现了幻觉;

大多数场景是我第一次读完后(可能是修改了某条数据后再读的),锁定了我读的那一条数据,但另一个事务改了这张表的其它数据,我第二次读的时候以为第一次读出现了幻觉(可能第一次修改了全表,另一个事务只改了一条数据,我以为我没成功修改那条数据);

 

三、隔离级别

 

  脏读 不可重复读 幻读
Read uncommitted 可能发生  可能发生 可能发生
Read committed   可能发生 可能发生
Repeatable read     可能发生
Repeatable read      

以上是关于数据库难点:脏读幻读不可重复读与四种隔离级别的主要内容,如果未能解决你的问题,请参考以下文章

数据库事务隔离级别脏读重复读不可重复读幻读

何为脏读不可重复读幻读

数据库事务隔离级别-- 脏读幻读不可重复读

数据库事务隔离级别-- 脏读幻读不可重复读(清晰解释)

MySQL数据库的脏读不可重复读幻读问题

什么是脏读不可重复读幻读?一文带你搞定MySQL事务隔离级别