事务隔离级别

Posted wzzkaifa

tags:

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

事务具有四个特征:原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持续性( Durability )。

这四个特性简称为 ACID 特性。 
1 、原子性 
事务是数据库的逻辑工作单位,事务中包括的各操作要么都做。要么都不做 
2 、一致性 
数据库事务不能破坏关系数据库的完整性以及业务逻辑上的一致性。
3 、隔离性 
一个事务的运行不能其他事务干扰。即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发运行的各个事务之间不能互相干扰。 
4 、持续性 
也称永久性。指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其运行结果有不论什么影响。

事务应用场景:

对于同一个银行帐户A内有200元,甲进行提款操作100元,乙进行转帐操作100元到B帐户。假设事务没有进行隔离可能会并发例如以下问题:

脏读(Dirty Read): 一个事务读到还有一个事务未提交的更新数据。

事务T1更新了数据还未提交,这时事务T2来读取同样的数据,则T2读到的数据事实上是错误的数据,即脏数据。基于脏数据所作的操作是不可能正确的 。

脏读:甲取款100元未提交,乙进行转帐查到帐户内剩有100元,这是甲放弃操作回滚,乙正常操作提交。帐户内终于为0元。乙读取了甲的脏数据,客户损失100元。

解读:甲进行回滚操作,账户将变成200元,乙进行正常提交,200元将被覆盖为0。故顾客损失100元

第一类丢失更新: 撤销一个事务时,把其它事务已提交的更新数据覆盖。

样例:首先甲提款时帐户内有200元,同一时候乙转帐也是200元,然后甲乙同一时候操作。甲操作成功取走100元。乙操作失败回滚,帐户内终于为200元。这样甲的操作被覆盖掉了,银行损失100元。

不可反复读(Nonrepeatable Read) :一个事务读到还有一个事务已提交的更新数据。


一个事务的两次读取中,读取同样的资源得到不同的值。当事务T2在事务T1的两次读取之间更新数据,则会发生此种错误。(重点在改动)

样例:甲乙同一时候開始都查到帐户内为200元,甲先開始取款100元提交,这时乙在准备最后更新的时候又进行了一次查询。发现结果是100元,这时乙就会非常困惑。不知道该将帐户改为100还是0。

幻读(虚读): 一个事务读到还有一个事务已提交的新插入的数据。

(解释一)

事务T1对一定范围内运行操作,T2对同样的范围内运行不兼容的操作,这时会发生幻读。 
如:T1删除符合条件C1的全部数据。T2又插入了一些符合条件C1的数据,则在T1中再次查找符合条件C1的数据还是能够查到,这对T1来说好像是幻觉一样。这时的读取操作称为幻读。(重点在新增或删除)事务T1对一定范围内运行操作,T2对同样的范围内运行不兼容的操作,这时会发生幻读。 
如:T1删除符合条件C1的全部数据,T2又插入了一些符合条件C1的数据,则在T1中再次查找符合条件C1的数据还是能够查到,这对T1来说好像是幻觉一样。这时的读取操作称为幻读。(重点在新增或删除)

如:是针对于插入操作过程中的读取问题,如丙存款100元未提交,这时银行做报表进行统计查询帐户为200元,然后丙提交了,这时银行再统计发现帐户为300元了,无法推断究竟以哪个为准?

大家好像认为统计这个东西肯定是时时更新的,这样的情况非常正常;可是假设统计是在一个事务中的时候就不正常了,比方我们的一个统计应用须要将统计结果分别输出到电脑屏幕和远程网络某台计算机的磁盘文件里,为了
提高性能和用户响应我们分成2个线程,这时先完毕的和后完毕的统计数据就可能不一致,我们就不知道以哪个为准了。


和脏读的差别是,脏读是读取前一事务未提交的脏数据,不可反复读是又一次读取了前一事务已提交的数据。

第二类丢失更新: 这是不可反复读的特例,一个事务覆盖还有一个事务已提交的更新数据。

如上,乙不做第二次查询而是直接操作完毕,帐户内终于为100元,甲的操作被覆盖掉了。银行损失100元。


在多个事务并发做数据库操作的时候,假设没有有效的避免机制,就会出现种种问题。

大体上有三种问题:

1、丢失更新说明事务进行数据库写操作的时候可能会出现的问题。

2、不可反复读说明了做数据库读操作的时候可能会出现的问题。

3、脏读

数据库系统採用锁来实现事务的隔离性。  

1、锁的基本原理例如以下

    A、当一个事务訪问某种数据库资源时,假设运行select语句,必须先获得共享锁;假设运行insert、update或者delete语句,必须获得独占锁。
    B、当第二个事务也要訪问同样的资源时。假设运行select语句,也必须先获得共享锁。假设运行inert、update或者delete语句。也必须先获得独占锁。此时依据已经放置在资源上的锁的类型,来决定第二个事务应该等待还是马上获取该锁。


    第二个事务获取锁的情况说明:

资源上已经放置的锁 第二个事务进行读操作 第二个事务进行更新操作
马上获得共享锁 马上获得独占锁
共享锁 马上获得共享锁 等待第一个事务解除共享锁
独占锁 等待第一个事务解除独占锁 等待第一个事务解除独占锁
2、锁的多粒度性及自己主动锁升级
    数据库系统可以锁定的资源包含:数据库、表、区域、页面、键值(指带有索引的行数据)、行。


    依照锁定资源的粒度,锁能够分为下面类型:
      A、数据库级锁:锁定整个数据库。
      B、表级锁:锁定一张数据库表。
      C、区域级锁:锁定数据库的特定区域。


      D、页面级锁:锁定数据库的特定页面。
      E、键值级锁:锁定数据库表中带有索引的一行记录。


      F、行级锁:锁定数据库表中的单行记录。
    锁的粒度越大,事务间的隔离性就越高,事务间的并发性能就越低。
    锁升级是指调整锁的粒度。将多个低粒度的锁替换成少数更高粒度的锁。以此来减少系统负荷。

3、锁的类型和兼容性
    A、共享锁:
      共享锁用于读数据操作。它是非独占的,同意其它事务同一时候读取其锁定的资源,可是不同意其它事务更新它。


    B、独占锁:
      独占锁也叫排他锁。适用于改动数据的场合。它所锁定的资源。其它事务不能读取也不能改动。
    C、更新锁:
      更新锁在更新操作的初始化阶段用来锁定可能要被改动的资源,这样能够避免使用共享锁造成的死锁现象。
    共享锁、独占锁、更新锁的特征总结:

特征项 共享锁 独占锁 更新锁
加锁条件

当一个事务运行select语句时,数据库会

为这个事务分配一个共享锁。来锁定被查询的数据。

事务运行inert、update、delete语句时,分配独占锁。

事务运行

update语句时

。分配更新锁

解锁条件

一般数据被读取后,数据库系统立马解除共享锁

。当查询多条记录时。也是一条一条的锁定-解锁。

独占锁直到事务结束才干被解除。

数据读取完成。

运行更新操作时

。会把更新锁升

级为独占锁。

与其它锁兼容性 假设数据资源上放置了共享锁。还能再放置共享锁和更新锁。

不能和其它锁兼容。

与共享锁兼容,

但仅仅能有一个更

新锁,这样能够

避免死锁

并发性能 具有良好的并发性能 并发性能较差  
更新锁

更 新 (U) 锁能够防止通常形式的死锁。一般更新模式由一个事务组成。此事务读取记录。获取资源(页或行)的共享 (S) 锁。然后改动行,此操作要求锁转换为排它 (X) 锁。假设两个事务获得了资源上的共享模式锁,然后试图同一时候更新数据。则一个事务尝试将锁转换为排它 (X) 锁。

共享模式到排它锁的转换必须等待一段时间,由于一个事务的排它锁与其他事务的共享模式锁不兼容;发生锁等待。第二个事务试图获取排它 (X) 锁以进行更新。由于两个事务都要转换为排它 (X) 锁。而且每一个事务都等待还有一个事务释放共享模式锁。因此发生死锁。


若要避免这样的潜 在的死锁问题,请使用更新 (U) 锁。

一次仅仅有一个事务能够获得资源的更新 (U) 锁。假设事务改动资源,则更新 (U) 锁转换为排它 (X) 锁。否则,锁转换为共享锁。

4、死锁及其防治方法

    在数据库系统中,死锁是指多个事务分别锁定一个资源。又试图请求锁定对方已经锁定的资源,这就产生了一个锁定请求环,导致多个事务都处于等待对方释放锁定资源的状态。


    很多数据库系统能自己主动定期搜索和处理死锁问题,当检測到锁定请求环时,系统将结束死锁优先级最低的事务,并撤销该事务。
    避免死锁的方法:
      A、合理安排表訪问顺序。
      B、使用短事务。
      C、假设对数据的一致性要求不是非常高,能够同意脏读。
      D、假设可能的话,错开多个事务訪问同样数据资源的时间,以防止锁冲突。
      E、使用尽可能低的事务隔离级别。


数据库的隔离级别

   

 数据库提供了4种事务隔离级别供用户选择:

隔离级别 是否有第一类丢失更新 是否出现脏读 是否出现虚读 是否出现不可反复读 是否出现第二类丢失更新
Serializable
Repeatable Read
Read Commited
Read Uncommited
Serializable(串行化):一个事务在运行过程中全然看不到其它事务对数据库所做的更新(事务运行的时候不同意别的事务并发运行。事务串行化运行,事务仅仅能一个接着一个地运行,而不能并发运行)。

Repeatable Read(可反复读):一个事务在运行过程中能够看到其它事务已经提交的新插入的记录,可是不能看到其它其它事务对已有记录的更新。

Read Commited(读已提交数据):一个事务在运行过程中能够看到其它事务已经提交的新插入的记录。并且能看到其它事务已经提交的对已有记录的更新。

Read Uncommitted(读未提交数据):一个事务在运行过程中能够看到其它事务没有提交的新插入的记录,并且能看到其它事务没有提交的对已有记录的更新。

          1、从应用程序的角度。锁能够分为2类
    A、悲观锁:指在应用程序中显式的为数据资源加锁。会影响并发性能。
    B、乐观锁:乐观锁假定当前事务操作数据资源时,不会有其它事务同一时候訪问该数据资源。因此全然依靠数据库的隔离级别来自己主动管理锁。
  2、悲观锁的实现方式
    A、在应用程序中显示指定採用数据库系统的独占锁来锁定数据源。


    B、通过在数据库表中添加一个标记字段,来推断事务能否够訪问。


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

Spring事务隔离级别:REQUIRES_NEW使用细节

MySQL的默认事务隔离级别是?

如何更改mysql事务隔离级别

mysql 的事务隔离级别 及各个隔离级别应用场景,详细

MySQL-8事务与隔离级别IO

数据库事务隔离级别 一般用哪个