资讯专栏INFORMATION COLUMN

数据库事务

svtter / 1262人阅读

摘要:确保持久性是数据库系统中称为恢复管理部件的软件部件责任。中止状态事务回滚并且数据库已恢复到事务开始执行前的状态之后。

  事务是构成单一逻辑工作单元的操作集合。即使有故障,数据库系统也必须保证事务的正确执行,即执行整个事务或属于该事务的操作一个也不执行。

一、事务概念

  事务是访问并可能更新各种数据项的一个程序执行单元。事务由事务开始(begin transaction)与事务结束(end transaction)之间执行的全体操作组成。为了保证数据完整性,要求数据库维护事务的以下性质:

原子性(atomicity):事务的所有操作在数据库中要么全部正确反映,要么全部不反映。

一致性(consistency):隔离执行事务时(即,在没有其他事物并发执行的情况下)保持数据库的一致性。

隔离性(isolation):尽管多个事务可能并发执行,但系统保证,对于任何一对事务Ti和Tj,在Ti看来,Tj或者在Ti开始之前已经完成执行,或者在Ti完成之后开始执行。这样,每个事务都感觉不到系统中有其他事务在并发地执行。

持久性(durability):一个事务成功完成之后,它对数据库的改变是永久的,即使系统可能出现故障。

  这些特性通常称为ACID特性。
设Ti是从账户A过户50美元到账户B的事务。这个事务可以定义为

Ti:read(A);
   A-=50;
   write(A);
   read(B);
   B+=50;
   write(B);
1.一致性

  一致性要求事务的执行不改变A、B之和。如果没有一致性要求,金额可能会被事务凭空创造或者销毁!如果数据库在事务执行前是一致的,那么事务执行后仍将保持一致性,这是很容易验证的。确保单个事务的一致性是编写该事务的应用程序员的责任,完整性约束的自动检查给这项工作带来了便利。如果系统的状态不再反映数据库本应描述的现实世界的真实状态,称之为不一致状态

2.原子性

  保证原子性的思路:对于事务要执行写操作的数据项,数据库系统在磁盘上记录其旧值,如果事务没能完成执行(如在事务执行过程中出现了故障),数据库系统将恢复其旧值,使得表面上事务从未执行过。保证事务的原子性是数据库系统本身的责任,具体而言是由事务管理部件保证的

3.持久性

  持久性保证事务一旦成功地完成执行,该事务对数据库所做的更新都是永久的,即使事务执行完成之后出现系统故障。现在假设计算机系统的故障会导致内存数据丢失,但已经写入磁盘的数据却不会丢失。可以通过确保以下两条中的任何一条来达到持久性:下面这两条都是指的在事务完成之后发生故障后信息不会丢失的手段。在这里持久性的事务完成应该包含了两重含义:一是在事务结束的时候更新也全部写入磁盘了,这样叫做事务完成。二是事务结束的时候并非所有更新都写入磁盘了,可能是部分也可能都没有,但 写入了哪些更新以及还有哪些没写入的更新 的信息是被写入到磁盘上了的,这样也叫做事务完成了。

事务做的更新在事务结束前就已经写入磁盘。

有关事务已执行的更新和已写到磁盘上的更新信息必须充分,能让数据库在数据库系统出现故障后重新启动时重新构造更新。

 
  确保持久性是数据库系统中称为恢复管理部件的软件部件责任。事务管理部件和恢复管理部件之间关系密切。

4.隔离性

  即使每个事务都能确保一致性和原子性,如果几个事务并发执行,它们的操作会以某种人们所不希望的方式交叉执行,这也会导致不一致的状态。一种避免事务并发执行而产生的问题的途径是串行地执行事务,但事务并发执行能显著地改善性能。因此人们提出了多种允许多个事务并发执行的解决方法。
  例如:以常用的mysql InnoDB存储引擎为例:加入商品表items表中有一个字段status,status=1表示该商品未被下单,status=2表示该商品已经被下单,那么我们对每个商品下单前必须确保此商品的status=1。假设有一件商品,其id为10000;如果不使用锁,那么操作方法如下:

   //查出商品状态
   select status from items where id=10000;
   //根据商品信息生成订单
   insert into orders(id,item_id) values(null,10000);
   //修改商品状态为2
   update Items set status=2 where id=10000;

  上述场景在高并发环境下可能出现问题: 前面已经提到只有商品的status=1是才能对它进行下单操作,上面第一步操作中,查询出来的商品status为1。但是当我们执行第三步update操作的时候,有可能出现其他人先一步对商品下单把Item的status修改为2了,但是我们并不知道数据已经被修改了,这样就可能造成同一个商品被下单2次,使得数据不一致。所以说这种方式是不安全的。
  事务的隔离性确保事务并发执行后的系统状态与这些事务一个接一个地执行后的状态是等价的。确保隔离性是数据库系统中并发控制部件来保证的。

二、事务状态

  中止事务:不能顺利完成的事务。
  回滚:为保证原子性,对中止事务对数据库所做过的所有更改进行撤销。
  已提交事务:成功完成执行的事务。
  补偿事务:撤销已提交事务所造成的影响的唯一方法,这种补偿事务是交给用户自己来编写和执行的。
  

  活动状态:初始状态;事务执行时处于这个状态。在活动状态中出现逻辑错误可能会进入失败状态
  部分提交状态:最后一条语句执行后。此时事务已经完成执行,但由于实际输出可能仍临时驻留在主存中,一个硬件故障可能可能阻止其成功完成,这个时候就会进入失败状态。
  失败状态:发现正常的执行不能继续之后。系统判定事务的无法正常进行后(由于硬件或逻辑错误),事务进入失败状态。失败状态的事务必须进行回滚,这样就进入了中止状态。
  中止状态:事务回滚并且数据库已恢复到事务开始执行前的状态之后。在中止状态中,系统有两种选择:1.重启事务:仅当引起事务中止的是硬件错误而不是事务的内部逻辑产生的软件错误时。重启事务看成是一个新事务。2.杀死事务:通常是由于事务的内部逻辑错误,只有重写应用程序才能改正,或者由于输入错误,或者所需数据在数据库中没有找到。
  提交状态:成功完成之后。

三、并发执行

  事务处理系统通常允许多个事务并发执行。如前所述,允许多个事务并发更新数据引起许多数据一致性的问题。然而有两条理由促使我们使用允许并发:

提高吞吐量和资源利用率。一个事务由多个步骤组成,一些步骤涉及IO活动,另一些涉及CPU活动。计算机系统中CPU和磁盘并行运作。因此IO活动可以与CPU处理并行进行。利用CPU与IO系统的并行性,多个事务可并行执行。当一个事务在一个磁盘上进行读写时,另一个事务可以在CPU上运行,同时第三个事务又可在另一磁盘上进行读写。从而吞吐量增加,即给定的时间内执行的事务数增加,相应地,处理器与磁盘利用率也提高,换句话说处理器与磁盘空闲的时间较少。

减少等待时间。如果事务串行执行,短事务可能必须等待它前面的长事务完成,这可能导致难以预测的延迟。如果各个事务是针对数据库的不同部分进行操作,事务并发执行可能会更好,各个事务可以共享CPU周期和磁盘存取。并发执行也能减少平均响应时间,即一个事务从开始到完成所需的平均时间。

  在数据库中使用并发执行后的动机本质上与操作系统中使用多道程序(multiprograming)的动机是一样的。

四、可串行化 1.串行调度和并发调度

  事务的调度可以分为串行调度并发调度

串行调度就是在执行事务时,是一个事务一个事务地执行,就是先按顺序执行完一个事务的所有指令,再去按顺序执行完另一个事务的所有指令。串行调度的缺点也就是对应于前面并发执行的两个理由。

并发调度就是并发执行多个事务时的调度,多个事务的各条指令可以交叉执行,一个处理器可能在多个事务之间进行上下文切换。并发调度存在问题是可能会造成数据库的不一致性,比如修改被覆盖(课件P6)、脏读、不可重复读、幻读等等。

       为了事务的一致性或者说数据库的一致性,其中的一种主要的思想就是并发调度执行的效果应该和没有并发调度执行的结果相同(也可以有其他方法详见数据库系统概念25章高级事务处理6.2并发控制)。这样的并发调度也被叫做可串行化的(并发)调度或者具有可串行性。这也是隔离性最强的级别的含义

2.冲突可串行化调度和视图可串行化调度

  为了实现这种并发调度的可串行化,两种可以充分保证可串行化的并发调度特例被提出了:冲突可串行化调度视图可串行化调度,即串行化调度包含冲突可串行化调度、视图串行化调度,其中视图串行化调度又包含冲突串行化调度。这两种串行化调度特例 就是保证可串行化调度的 多种并发控制机制的基础。
  指令(操作)冲突的定义如下图所示,同一事务的指令之间是不能交换顺序的因此也看作是冲突的,当两个不同事务的对同一数据项的两条指令都是read的时候两者才是不冲突的。来自不同事务的两指令,只要其中一条指令是write的那么,就是互为冲突指令。反之,则互为非冲突指令。如果调度S可以经过一系列非冲突指令交换转换成S",我们称S和S"是冲突等价的。若一个调度S和一个串行调度冲突等价,那么则称调度S是冲突可串行化的


  
数据库中为了并发调度后保证一致性的并发控制部件,可以采取多个并发机制来实现串行化从而保证一致性,准确地说是某些机制只允许产生冲突可串行化调度,而另一些则允许产生非冲突可串行化的视图可串行化调度。接下来要讲到的并发控制协议有基于锁的协议(两段封锁协议和基于图的封锁协议)、基于时间戳的协议、基于有效性检查的协议

3.冲突可串行性判别算法

构造一个前驱图(有向图)

结点是每一个事务Ti。如果Ti的一个操作与Tj的一个操作发生冲突,且Ti的操作在Tj的操作前执行,则绘制一条边,由Ti指向Tj, 表征Ti要在Tj前执行。

测试检查: 如果此有向图没有环,则是冲突可串行化的!

五、事务隔离性级别

  保证可串行化是隔离性的最高级别,可串行性允许程序员在对事务编写代码时忽略与并发性相关的问题,是一个有用的概念。如果说没有隔离性要求的事务能让事务在独立执行时保证数据库的一致性,那么加上有了最高级别的隔离性(即可串行化)的事务就能保证事务在并发执行时也能保证数据库的一致性。
  但可串行化的缺点在于对于一些应用而言,遵守保证可串行性的那些协议意味着可能就只能允许极小的并发性了。在这种情况下,我们采用较弱级别的隔离性即不能从数据库系统上来保证完全的一致性了或者说保证了较弱级别的一致性,要想保证完全的一致性则需要程序员在编写事务代码注意了,所以说使用较弱级别一致性给程序员增加了额外负担。
  隔离性级别可以分为从强到弱可以分为:可串行化可重复读已提交读未提交读。也对应着从强到弱的一致性级别。关于四种隔离级别锁实现的原理可参看Innodb中的事务隔离级别和锁的关系

  
  违反可串行化的三种现象,也是可能破坏数据库一致性的三种异常现象避免词不达意就不翻译了:定义参照《sql92标准》以及论文《A Critique of ANSI SQL Isolation Levels》,论文中对SQL92中的标准中定义模糊的地方提出了批评并对隔离级别和异常现象做出了更精准的描述。ps:SQL92标准找到了txt版本的,更新的SQL标准基本上都不是免费的了,找了无果之后没有继续再找。想要继续了解SQL标准可以先看看谈谈SQL标准

脏读(dirty read):SQL-transaction T1 modifies a row. SQL-transaction T2 then reads that row before T1 performs a COMMIT.If T1 then performs a ROLLBACK, T2 will have read a row that was never committed and that may thus be considered to have never existed.

不可重复读(nonrepeatable read):SQL-transaction T1 reads a row. SQL-transaction T2 then modifies or deletes that row and performs a COMMIT. If T1 then attempts to reread the row, it may receive the modified value or discover that the row has been deleted.

幻读(phantom read):SQL-transaction T1 reads the set of rows N that satisfy some . SQL-transaction T2 then executes SQL-statements that generate one or more rows that satisfy the used by SQL-transaction T1. If SQL-transaction T1 then repeats the initial read with the same , it obtains a different collection of rows.

 
  三种其实都是读取到的数据不一致:

脏读是读到了根本从未在数据库中存在过得数据。

不可重复读是一次事务中前后两次相同的读取,第二次的读取相比第一次,结果被删除了或者被更改了。可以看到这种不可重复读的情况是不违背读已提交的,即在保证了脏读不会发生而仍然可以发生不可重复读的

幻读就是一个事务中的两次相同查询条件的读取,第二次相比第一次发现读取到的结果集变多了。可以看到在保证了第二种情况不会发生的情况下,两次相同查询条件的查询,第一次查询到的那些记录肯定不会消失(即不可重复读中的被修改或删除造成的,现保证其不会发生了),但并不能保证记录集不会增多。如当其他事务在这期间插入了新的满足查询条件的记录,那么第二次查询的时候就会发现,虽然第一次查询的结果时都在的,但也莫名其妙多了一些。也就是说可重复读的情况下,幻读仍然是可能发生的

       在论文中给出的更严格的隔离级别与异常现象,及其两者更完整的关系:详情参阅论文以及数据库事务隔离发展历史


 
  注意上图中的论文中重新严格定义的四种异常现象当中的write并非仅是修改,不可重复读当中的write与SQL92标准中相同是包含修改、删除,而幻读当中的write则不光包含92标准中的插入还包含删除、修改
参考文献:
再谈数据库事务隔离性
MySQL时间线,MySQL 4.1/5.0/5.1/5.5/5.6/5.7各版本的主要特性和区别

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/17817.html

相关文章

  • 【深入浅出事务】(3):事务的隔离级别(超详细)

    摘要:客户端设置手动提交,修改事务隔离级别为,并且开启事务一定要在开启事务前修改事务的隔离级别,不然当前还是保持着原来的事务隔离级别,直到当前事务提交。 本质 隔离级别定义了数据库系统中一个操作产生的影响什么时候以哪种方式可以对其他并发操作可见,隔离性是事务的ACID中的一个重要属性,核心是对锁的操作。 锁 从数据库系统角度 共享锁(Shared Lock) 读锁,保证数据只能读取,不能被修...

    zhangrxiang 评论0 收藏0
  • 据库 - 事务管理(ACID)隔离级别 事务传播行为

    摘要:关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。这种现象也是正常的,是由于事务的隔离级造成的,但是在在某些特别的情况下也是不允许的。指定业务方法绝对不能在事务范围内执行。内部事务的回滚不会对外部事务造成影响。 总览:showImg(https://segmentfault.com/img/bV3dRF?w=677&h=676); 事务的4大特性(ACID) 原子性(Atomic...

    lansheng228 评论0 收藏0
  • Spring事务整理

    摘要:使用需要使用作为事务管理器。两个事务互不影响。这是默认的隔离级别,使用数据库默认的事务隔离级别下边的四个与的隔离级别相对应这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种事务隔离级别可 Spring事务整理 工作了几年了,今天抽时间整理一下spring的事务,说起spring的事务是面试的时候面试官经常提及的问题,接下来结合网上资料再总结下spring的事务...

    stackvoid 评论0 收藏0
  • 可能是最漂亮的Spring事务管理详解

    摘要:事务隔离级别定义了一个事务可能受其他并发事务影响的程度我们先来看一下并发事务带来的问题,然后再来介绍一下接口中定义了五个表示隔离级别的常量。 Java面试通关手册(Java学习指南):https://github.com/Snailclimb/Java_Guide 微信阅读地址链接:可能是最漂亮的Spring事务管理详解 事务概念回顾 什么是事务? 事务是逻辑上的一组操作,要么都执行,...

    邹立鹏 评论0 收藏0
  • Spring中的事务控制

    摘要:中的事务控制方式编程式事务管理通过手动编码控制事务的边界,可以实现细粒度的事务控制,一般用的较少。隔离级别控制并发访问下数据库的安全性。内部事务的回滚不会对外部事务造成影响。可能导致脏幻不可重复读允许在并发事务已经提交后读取。 1.事务的概念 事务是一组操作的执行单元,相对于数据库的单条操作而言,事务管理的是一组SQL指令,如增删改查等,事务的特性体现在事务内包含的SQL指令必须全部执...

    Vixb 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<