数据库隔离级别详解

6.3 隔离级别

隔离级别解决的是,多个事务访问同一数据时出现的不一致的一系列问题。

6.3.1 数据库事务的知识

数据库事务具有以下4个基本特征:也就是著名的 ACID。

Atomic(原子性):事务中包含的操作被看作一个整体的业务单元,这个业务单元的所有操作要么全部成功,要么全部失败,不会出现部分成功、部分失败的场景。

Consistency(一致性):事务在完成时,必须使所有的数据都保持在一直的状态,在数据库中所有的修改都是基于事物的,保证了数据的完整性。

Isolation(隔离性):多个应用程序同时访问同一数据,这样数据库同样的数据就会在不同事务中被访问,这样就会产生丢失更新。为了压制丢失更新的产生,数据库定义了隔离级别的概念,通过它的选择,可以在不同程度上压制丢失更新的发生。因为互联网的应用常常是面对高并发的场景,所以隔离性是需要掌握的重点内容。

Durability(持久性):事务结束后,所有数据都会固化到一个地方,如保存在磁盘中,即使断电重启后也可以提供给应用程序访问。

第一类丢失更新

一个事物回滚另外一个事务提交而引发的数据不一致的情况,我们称之为第一类丢失更新。

发生原因两个事务是独立的,都从相同的数据源获取数据,彼此之间没有相互约束,就会造成访问修改相同的数据出错。如下场景。

时刻事务1事务2
T1初始库存100初始库存100
T2扣减库存,剩余99
T3扣减库存,剩余99
T4提交事务,库存变为99
T5回滚事务,库存100

不过现今,这种情况已经没有讨论价值了,因为目前主流的数据库都已经克服了第一类丢失更新问题。

第二类丢失更新

多个事务都提交引发的丢失更新被称之为第二类丢失更新。

解决第二类丢失更新的原则就是,事务之间不再是相互独立的,而是彼此之间的是有约束的,按约束等级不同,能解决的更新丢失的级别也会越高,最高级别的约束会完全防止丢失更新,但是付出的代价的就是性能的下降,所以要合理使用隔离级别

6.3.2 详解隔离级别

为了压制丢失更新,我们需要使用隔离级别。隔离级别有四个:未提交读、读写提交、可重复读、串行化(按照由低到高的级别进行的排序)。

  1. 未提交读

    级别:1

    含义:允许一个事务去读取另一个事务未提交的数据的数据,造成的结果是:脏读。一个场景如下。

    时刻事务一事务二备注
    T1商品库存初始化为2
    T2读取库存为2
    T3扣减库存库存为1
    T4扣减库存库存为0,读取事务一未提交的库存数据1,扣减之后为0
    T5提交事务库存保存0
    T6回滚事务因为第一类丢失更新已经克服,所以不会回滚事务为2,库存为0,结果错误。

    脏读是比较危险的隔离级别(由上表也可以看到,存储的数据出现了错误),所以实际中一般不用这个隔离级别。

  2. 读写提交

    级别:2

    含义:一个事务只能读取另外一个事务已经提交了的数据,不能读取未提交的数据。

    克服脏读:

    时刻事务一事务二备注
    T1商品库存初始化为2
    T2读取库存为2
    T3扣减库存库存为1
    T4扣减库存库存为1,读取不到事务1未提交的库存数据,只能获得从数据库读到的2
    T5提交事务库存保存为1
    T6回滚事务因为第一类丢失更新已经克服,所以不会回滚事务为2,库存为1(就是事务二的操作结果),结果正确。

    可以看到上面已经克服了脏读,但是读写提交,会发生不可重复读的情况,如下。

    不可重复读:

    时刻事务一事务二备注
    T1商品库存初始化为1
    T2读取库存为1
    T3扣减库存事务一未提交
    T4读取库存为1事务二不能读取事务一未提交的0,所以只能读取数据库中的1,认为可扣减
    T5提交事务事务一提交之后库存变为0,但是此时事务二还以为库存为1
    T6扣减库存失败,因为此时库存为0,无法扣减.(可以看出扣减操作,不是扣减的读取到的临时值,而是操作的数据库中数据对应的地址),数据正确。

    这种情况叫做不可重复度,但是可以看到虽然事务二的操作失败了,但是数据本身是正确的。产生的原因本质还是数据不同步而已。

  3. 可重复读

级别:3

含义:就是当其中一个事务在操作与自己要操作的相同数据的时候,由于加锁的缘故自己不被允许的读取该数据,所以可以等一会再尝试读取,这就叫做可重复读。解决了读写提交中的不可重复读的情况。

克服不可重复度:

时间事务一事务二备注
T0商品初始化为1
T1读取库存1
T2扣减库存事务1未提交
T3尝试读取库存不允许读,等待事务1的提交
T4提交事务库存变为0
T5读取库存库存为0,无法扣减

可以看到,其实就是对多个事务操作相同的数据时,对该数据进行加锁,同一时刻只有先到的事务才能操作数据(读写)。但是这个级别也并不是完美的,其还会产生幻读,如下:

幻读:

时间事务一事务二备注
T0读取库存50件商品库存初始化为100,现在已经销售50笔,库存50笔
T1查询交易记录,50笔
T2扣减库存
T3插入1笔交易记录
T4提交事务库存49件,交易记录51件
T5打印交易记录,51笔这里与查询不一致,在事务2看来有1笔是虚幻的,与之前查询的不一致。

这里的笔数不是数据库存储的值,而是一个统计值,商品库存则是数据库存储的值,这一点时要注意的。也就是说幻读不是针对一条数据库记录而言的,而是多条记录,例如,这51笔交易比数就是多条数据库记录统计出来的。而可重复度是针对数据库的但一条记录,例如,商品的库存是以数据库里面的一条记录存储的,他可以产生可重复度,而不能产生幻读。

  1. 串行化

级别:4(也就是最高级别)

含义:就是要求所有的 SQL 都按照顺序执行,这样就可以克服上述隔离级别出现的各种问题,所以他能够完全保证数据的一致性。但是这样就会使性能严重下降。

  1. 使用合理的隔离级别

    隔离级别和可能发生的现象

    项目类型脏读不可重复读幻读
    未提交读
    读写提交X
    可重复度XX
    串行化XXX

在现实中一般而言,选择隔离级别会议读写提交为主,它能够防止脏读,而不可避免不可重复读和幻读。为了克服数据不一致和性能问题,程序开发者还设计了乐观锁,甚至不再使用数据库而使用其他手段。例如,使用 Redis 作为数据载体。

对于隔离级别,不同的数据库至此也是不一样的。例如,Oracle 只能支持读写提交串行化,而 MySQL 则支持上述四种,对于 Oracle 默认的隔离级别为读写提交,MySQL 则是可重复读,这些需要根据具体数据库来做决定。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值