数据库事务的四种隔离级别

Posted Allen----Liu

tags:

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

1.引言

数据库事务的隔离级别有4种,由低到高分别为Read uncommitted(读未提交) 、Read committed (读已提交)、Repeatable read (重复读)、Serializable (序列化)。读现象是在多个事务并发执行时,在读取数据方面可能碰到的问题。包括脏读、不可重复读、幻读。

脏读:读到了脏数据,即无效数据。

不可重复读:是指在数据库访问中,一个事务内的多次相同查询却返回了不同数据。

幻读:指同一个事务内多次查询返回的结果集不一样,比如增加了行记录。

备注:不可重复读对应的是修改,即update操作。幻读对应的是插入操作。幻读是不可重复读的一种特殊场景。

要想解决脏读、不可重复读、幻读等读现象,那么就需要提高事务的隔离级别。但是随之带来的,隔离级别越高,并发能力越低。所以,需要根据业务去进行衡量,具体场景应该使用哪种隔离级别。

下面通过事例一一阐述它们的概念与联系。

2.事务隔离级别

2.1 Read uncommitted(读未提交)

提供了事务建最小限度的隔离。顾名思义,就是一个事务可以读取另一个未提交事务的数据。

示例:小明去商店买衣服,付款的时候,小明正常付款,钱已经打到商店老板账户,但是小明发起的事务还没有提交。就在这时,商店老板查看自己账户,发现钱已到账,于是小明正常离开。小明在走出商店后,马上回滚差点提交的事务,撤销了本次交易曹邹。

结果:小明未付钱买到了衣服,商店老板实际未收到小明的付款。

分析:商店老板查看自己的资金账户,这个时候看到的是小明还没有提交事务的付款。这就是脏读。

注意:处于该隔离级别的事务A与B,如果事务A使用事务B不提交的变化作为计算的基础,然后哪些未提交的变化被事务A撤销,这就导致了大量的数据错误变化。

2.2 Read committed (读已提交)

处于Read committed (读已提交)级别的事务可以看到其他事务对数据的修改。也就是说,在事务处理期间,如果其他事务修改了相应的表,那么同一个事务的同一sql在其他事务执行前后返回的是不同的结果。一个事务要等另一个事务提交后才能读取数据。

示例:小明卡里有1000元,准备与几个朋友聚餐消费,消费1000元,当他买单时(事务开启),收费系统检测到他卡里有1000元。就在检测完毕的时候,小明女朋友发现小明有私房钱,全部转走并提交。当收费系统准备扣款时,再检查小明卡里的金额,发现已经没钱了,付款不成功。小明此时就会很纳闷,明明有钱的呀,钱呢?

分析:该示例中同一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。该隔离级别可以解决脏读问题。

2.3 Repeatable read (重复读)

在开始读取数据(事务开启)时,不再允许修改操作

示例:还是小明有1000元,准备跟朋友聚餐消费这个场景,当他买单(事务开启)时,收费系统检测到他卡里有1000元,这个时候,他的女朋友不能转出金额。接下来,收费系统就可以扣款成功了,小明醉醺醺的回家,准备跪脱衣板。

分析:重复读可以解决不可重复读的问题,这句话有些别扭,大家可以仔细品一下。

写到这里,大家可能会产生疑问,什么情况下产生幻读呢?

示例来了:

小明在公司上班,女朋友告诉他,拿着他的卡去逛街消费。花了一千元,然后小明去查看他银行卡的消费记录(事务开启),看到确实是花了一千元。就在这个时候,小明女朋友又花三千元买了一些化妆品和衣服,即新增了一些消费记录。当小明打印自己银行卡消费记录单的时候(女朋友事务提交),发现花了四千元,似乎出现了幻觉,小明很心疼。这就是幻读

扩展:当我们开启一个事务以后,有如下的程序操作

第一步:更新A表id=1的记录

第二步:查询A表id=1的记录

第三步:使用第二步的查询结果作为依据继续业务逻辑

第四步:提交事务

问题来了:同一个事务中,事务未提交前,第二步的查询结果是第一步执行前的结果还是第一步执行后的结果呢?

答案:事务隔离级别是针对不通事务的,同一事务中的未提交的更新,在后续是可以查询到的。

2.4 Serializable (序列化)

数据库事务的最高隔离级别。在此级别下,事务串行执行。可以避免脏读、不可重复读、幻读等读现象。但是效率低下,耗费数据库性能,不推荐使用。

3.mysql事务隔离级别查询

3.1mysql查看数据库实例默认的全局隔离级别sql

Mysql8以前:SELECT @@GLOBAL.tx_isolation, @@tx_isolation;

Mysql8开始:SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation;

3.2修改隔离级别命令:

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

建议开发者在修改时,仅修改当前session隔离级别即可。

3.3mysql默认隔离级别

REPEATABLE-READ,可以避免脏读,不可重复读,不可避免幻读

事务的四种隔离级别

数据库事务的隔离级别有4种,由低到高分别为Read uncommitted 、Read committed 、Repeatable read 、Serializable 。而且,在事务的并发操作中可能会出现脏读,不可重复读,幻读。下面通过事例一一阐述它们的概念与联系。


Read uncommitted

读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。

事例:老板要给程序员发工资,程序员的工资是3.6万/月。但是发工资时老板不小心按错了数字,按成3.9万/月,该钱已经打到程序员的户口,但是事务还没有提交,就在这时,程序员去查看自己这个月的工资,发现比往常多了3千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成3.6万再提交。

分析:实际程序员这个月的工资还是3.6万,但是程序员看到的是3.9万。他看到的是老板还没提交事务时的数据。这就是脏读。


那怎么解决脏读呢?Read committed!读提交,能解决脏读问题。


Read committed

读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。

事例:程序员拿着银行卡去享受生活(卡里当然是只有3.6万),当他埋单时(程序员事务开启),收费系统事先检测到他的卡里有3.6万,就在这个时候!!程序员的妻子要把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待妻子转出金额事务提交完)。程序员就会很郁闷,明明卡里是有钱的…

分析:这就是读提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。


那怎么解决可能的不可重复读问题?Repeatable read !


Repeatable read

重复读,就是在开始读取数据(事务开启)时,不再允许修改操作

事例:程序员拿着银行卡去享受生活(卡里当然是只有3.6万),当他埋单时(事务开启,不允许其他事务的UPDATE修改操作),收费系统事先检测到他的卡里有3.6万。这个时候他的妻子不能转出金额了。接下来收费系统就可以扣款了。

分析:重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。


什么时候会出现幻读?

事例:程序员某一天去消费,花了2千元,然后他的妻子去查看他今天的消费记录(全表扫描FTS,妻子事务开启),看到确实是花了2千元,就在这个时候,程序员花了1万买了一部电脑,即新增INSERT了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现花了1.2万元,似乎出现了幻觉,这就是幻读。


那怎么解决幻读问题?Serializable!


Serializable 序列化

Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

 

以上是关于数据库事务的四种隔离级别的主要内容,如果未能解决你的问题,请参考以下文章

MySQL数据库中的四种隔离级别

事务的四种隔离级别

数据库事务的四种隔离级别

数据库事务的四种隔离级别

MySQL 事务的四种隔离级别

数据库的四种隔离级别和事务的四特性