【数据库理论】事务、数据异常与隔离级别(精华版)

1970 年,IBM 的研究员 Edgar F.Codd 发表了《A Relational Model of Data for Large Shared Data Banks》 论文,提出了关系数据模型的概念,奠定了关系数据模型的理论基础,这是数据库发展史上具有划时代意义的里程碑。随后,Edgar F.Codd又陆续发表了多篇文章,论述了范式理论,用数学理论奠定了关系数据库的基础。

因此,学习关系代数和关系模型是成为学习数据库乃至计算机专业的基础。有关此方面的内容,请读者自行了解。

一、事务

1.1 通俗定义

事务( Transaction) 是(访问或操作一个或多个数据项的)一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个逻辑上不可分割的工作单元(Unit)。事务由事务开始与事务结束之间执行的全部数据库操作组成。

1.2 ANSI/ISO SQL 标准中“事务”的定义

事务的宽松定义只强调了“事务是由一组数据库操作组成的不可分割的逻辑单元”。

ANSI SQL 标准在此基础上,明确提出了事务“要么全部成功,要么全部失败”的两种状态。ANSI SQL 标准对 “SQL-事务” 的定义为:

SQL-事务(有时简称为“事务”)是一系列 SQL 语句执行,这些 SQL 语句执行在恢复方面是原子的。这些操作由一个或多个编译单元和模块(<module>)或通过直接调用 SQL 执行。

它是由是否允许 SQL-数据 语句的非动态或动态执行,或 <SQL dynamic data statement> 的执行发生在与 SQL-模式 语句的非动态或动态执行相同的 SQL 事务中的 实现定义的(Implementation-Defined)。如果确实发生了,那么对任何打开的游标、准备好的动态语句或延迟约束的影响都是由实现定义的。可能还有其他实现定义的限制、要求和条件。如果违反了任何此类限制、要求或条件,则会引发实现定义的异常条件或带有实现定义的子类代码的完成条件警告。”

注释
实现定义的(Implementation-Defined) 表示在不同的实现中可能存在差异,但实现者必须就每个特定的实现作出明确说明。

ANSI SQL-92 引文
4.28 SQL-transactions
An SQL-transaction (sometimes simply called a “transaction”) is a sequence of executions of SQL-statements that is atomic with respect to recovery. These operations are performed by one or more compilation units and <module>s or by the direct invocation of SQL.
It is implementation-defined whether or not the non-dynamic or dynamic execution of an SQL-data statement or the execution of an <SQL dynamic data statement> is permitted to occur within the same SQL-transaction as the non-dynamic or dynamic execution of an SQL-schema statement. If it does occur, then the effect on any open cursor, prepared dynamic statement, or deferred constraint is implementation-defined. There may be additional implementation-defined restrictions, requirements, and conditions. If any such restrictions, requirements, or conditions are violated, then an implementation-defined exception condition or a completion condition warning with an implementation-defined subclass code is raised.

由上可知,ANSI SQL 标准中事务的定义依赖于 DBMS 的具体的实现。

更多信息,请参阅第三方网站 https://datacadamia.com/_media/data/type/relation/sql/sql1992.txt 提供的 SQL-92 文档中 4.28 SQL-transactions 章节。

为什么不使用 ANSI 或 ISO 官网的文档?

  1. ANSI 收费www.ansi.org 官网中的 ANSI SQL-92 需要付费才能下载查阅。
  2. ISO 显示 1992版本已停止提供。最新版本的 《ISO/IEC DIS 9075》 仍在调研中,且即便可以查看 2016 版的,想要查看全部内容也是要收费的。

1.3 补充定义:引入事务的 ACID 特性

Jim Gray 在 ANSI SQL 标准的基础上,又提出了事务的 ACID 四个特性:“A transaction is a group of SQL commands whose results wi ll be made visible to the rest of the system as a unit when the transaction commits 一 not at all, if the transaction aborts. Transactions are expected to be atomic,consistent, isolated, and durable.

ACID 的定义如下:

  • 原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么全部不执行。
  • 一致性(Consistency):并发执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。
  • 隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。
  • 持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。

1.4 事务的作用

一个数据库事务通常包含了一系列的对数据库的读/写操作。它的存在包含有以下两个目的:

  • 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
  • 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。

二、预备知识

2.1 历史模型

历史模型 的符号定义如下:

  • H 表示某一历史。
  • 操作的符号定义包括:
    • r 即 read,表示读;
    • w 即 write,表示写;
    • c 即 commit,表示提交;
    • a 即 abort ,表示中断;
    • rc 即 read cursor ,表示读取游标;
    • wc 即 write cursor , 表示写入游标。
  • 操作后的下标数字表示事务标识。
  • 紧接着的是一对方括号(“[]”)或圆括号(“()”)。
  • 方括号内的是表达式或元组,表达式可以是数据项,谓词,或数据项、谓词和值组成的表达式;元组即 (数据项, 值) ,值可能为 init(初始版本或未出生版本)或 dead (死亡版本)。

例如, w 1 w_1 w1[x] 表示 事务 1数据项 x 上的写操作; r 2 r_2 r2[x] 表示 事务 2 对 x 的读操作。事务 1 读取和写入满足 谓词 P 的一组数据项分别表示为 r 1 r_1 r1[P] 和 w 1 w_1 w1[P] 。事务 1 的提交和中断分别表示为 c 1 c_1 c1 a 1 a_1 a1

2.2 数据对象

数据库由可被事务读取或写入的对象组成;在关系型数据库系统中,每个行或元组就是一个对象。每个事务读取和写入对象,并显示一个该事务中这些操作的全序关系。

对象可以有一个或多个版本。事务仅根据对象与数据库交互;系统将对象上的每个操作映射到该对象的特定版本。一个事务可以读取由提交的、未提交的、甚至是中断的事务创建的版本;某些隔离级别施加的约束会阻止某些类型的读取,例如,阻止读取已中断事务创建的版本。

当一个事务读取一个对象 x ,它创建一个 x 的新版本。一个事务 T i T_i Ti 可以多次修改一个对象;它对对象 x 的第一次修改表示为为 x i . 1 x_{i.1} xi.1 ,其中 i.1 为下标。以此类推,第二次修改表示为 x i . 2 x_{i.2} xi.2 ,等等。版本 x i x_i xi 表示事务 T i T_i Ti 在提交或中断前对 x 的最终修改版本。一个事务的最后一个操作(提交或中断)表示它的执行是否成功;每个事务最多有一次提交或中断操作。

提交状态 反映了已提交事务的修改。事务 T i T_i Ti 提交时,每个由事务 T i T_i Ti 创建的版本 x i x_i xi 成为提交状态的一部分,则称 T i T_i Ti 建立(install)了 x i x_i xi ;系统决定了 x i x_i xi 相对于 x 的其他版本的顺序。如果 T i T_i Ti 中断了, x i x_i xi 则不会成为提交状态的一部分。

概念上,初始提交状态由运行一个初始化事务 T i n i t T_{init} Tinit 的结果实现。事务 T i n i t T_{init} Tinit 创建将会存在于数据库中的所有对象;此时,每个对象 x 都有一个初始版本 x i n i t x_{init} xinit ,称为 未出生(unborn) 版本。当一个应用事务创建了一个对象 x ,例如通过插入一个元祖,,我们将其建模为创建 x 的一个 可见(visible) 版本。因此,加载数据库的事务创建要插入的对象的初始可见版本。当一个事务 T i T_i Ti 删除了一个对象 x ,例如通过删除某个关系中的一个元组,我们将其建模为创建 x 的一个特殊 死亡(dead) 版本。因此,存在三种对象版本:未出生, 可见,和死亡

如果一个对象 x 被从已提交数据库状态中删除后又再次插入了,我们认为 x 的两个化身是不同的对象。当一个事务 T i T_i Ti 执行了一个插入操作,系统选择一个以前从未被插入操作选择过的 唯一 对象 x ,并且如果 T i T_i Ti 提交了则会创建一个 x 的可见版本。

假设对象版本永远处于提交状态,以简化插入和删除的处理。一般情况下,除非特别声明,仅读取对象的可见版本。

2.2.1 数据项

数据项(Data Item) 表示单个数据记录,即,表行,由一个或多个 字段 组成。字段 是数据库系统支持的或用户自定义的数据类型在该表(关系)定义上的实例。

数据项 的广义解释:它可以是一个表行、一个页面、整个表或一个队列上的消息。

2.2.2 谓词

谓词(Predicate),简单来讲,就是可能由一个或多个 数据项 组成的集合。

谓词 P 表示布尔(Boolean)条件(例如,在 SQL 语句的 WHERE 子句中)和必须应用该条件的关系(即 表);可以在 P 中指定一个或多个关系。

基于谓词操作的版本集(Version Set)
当一个事务执行一个基于谓词 P 的读取或写入时,系统为在 P 的关系中的 每个 元组选取一个版本。被选择版本的集合被叫做这个谓词操作的 版本集 ,使用 Vset(P) 表示。

基于谓词的操作分为 谓词读谓词写 。基于谓词的操作会读取谓词 P 的版本集中的所有版本,既包括可见版本,又包括不可见版本(即未出生和死亡版本),然后选择匹配谓词 P 的可见版本。如果实际发生了读取,则后跟一个独立的读/写操作,否则不会执行额外的读/写操作,比如 SELECT COUNT 语句。

谓词读:读取满足谓词 P 条件的所有可见版本,即 r i r_i ri(P: Vset(P)) r i r_i ri( x i x_i xi) , x i x_i xiVset(P)

谓词写:读取满足谓词 P 条件的所有可见版本后写入该对象,即 r i r_i ri(P: Vset§) w i w_i wi( x i x_i xi) ,其中 x i x_i xi 可能是初始版本 x i n i t x_{init} xinit (对应插入操作) , x d e a d x_{dead} xdead (对应删除操作),或二者之间的某一版本 x i x_i xi (对应更新操作)。

2.3 依赖图

特定的历史会产生一个 依赖图(Dependency Graph) ,定义事务之间的时序数据流。历史中已提交事务的操作表示为图 节点(Nodes)。如果事务 T 1 T_1 T1 的操作 o p 1 op_1 op1 在历史中与发生在其之前的事务 T 2 T_2 T2 的操作 o p 2 op_2 op2 冲突,则这对 < o p 1 op_1 op1, o p 2 op_2 op2> 形成依赖图中的 边(Edges)。如果两个历史具有相同的已提交事务和相同的依赖图,则它们是等效的。如果一个历史与一个 串行(Serial) 历史等价,即,如果它与在序列中一次执行一个事务的某个历史具有相同的依赖图(跨事务(Inter-Transaction) 时序数据流),则称该历史是 可串行(序列)化(Serializable) 的。

2.4 冲突和序列化图

首先定义数据库系统中可能发生的不同类型的读/写冲突,然后使用它们来定义序列化图。我们定义了三种 直接冲突(Direct Conflicts) ,它们捕获了同一对象上两个不同提交事务或交叉谓词的冲突。为了方便起见,我们将基于谓词的冲突和常规冲突的定义分开了。

以下假设存在两个事务 T i T_i Ti T j T_j Tj T j T_j Tj 发生于 T i T_i Ti 之后,定义依赖的视角是 T j T_j Tj 相对于 T i T_i Ti 来说的,主体是 T j T_j Tj ,参照物是 T i T_i Ti 。而序列化图的显示结果却刚好相反,是按照原始的全序关系绘制从 T i T_i Ti T j T_j Tj 的依赖边。

例如, T j T_j Tj 直接读依赖于 T i T_i Ti ;而序列化图却显示为 T i → w r T j T_i \xrightarrow{wr} T_j Tiwr Tj ,其中 T i T_i Ti 先执行 w(写), T j T_j Tj 后执行 r(读)。反过来则是反依赖。

2.4.1 冲突

如果历史中的两个操作是在同一数据项上的不同事务执行的,并且其中至少有一个是写入操作,则称历史中的这两个操作 冲突(Conflict)。冲突的操作既可能发生单个数据项上,也可能发生在由 谓词锁(Predicate Lock) 保护的一组数据项上。

2.4.1.1 读依赖

读依赖发生在当一个事务读取另一个事务产生的相关版本时。使用如下定义来定义读依赖:

定义 2 :更改谓词读的匹配项。
如果 T i T_i Ti 建立了 x i x_i xi ,在版本顺序中, x h x_h xh 紧跟在 x i x_i xi 之前, x h x_h xh 与 P 匹配而 x i x_i xi 不匹配,或者相反,则称事务 T i T_i Ti 会更改谓词读 r j r_j rj(P: Vset(P)) 的匹配。在这种情况下,也称 x i x_i xi 更改了谓词读的匹配。

上述定义将 T i T_i Ti 标识为对 r j r_j rj(P: Vset(P)) 匹配的集所做的更改发生于其中的事务。

定义 3 :直接读依赖(Directly Read-Depends)。
如果事务 T j T_j Tj 直接项目读依赖直接谓词读依赖 于 事务 T i T_i Ti ,则称 T j T_j Tj 直接读依赖 T i T_i Ti

直接项目读依赖(Directly Item-Read-Depends):如果 T i T_i Ti 建立了某个对象版本 x i x_i xi ,并且 T j T_j Tj 读取了 x i x_i xi ,则称 T j T_j Tj 直接读依赖 T i T_i Ti
直接谓词读依赖(Directly Predicate-Read-Depends):如果 T j T_j Tj 执行一个操作 r j r_j rj(P: Vset(P)), x k x_k xkVset(P), i = k 或 x i x_i xi << x k x_k xk ,并且 x i x_i xi 更改了 r j r_j rj(P: Vset(P)) 的匹配,则称 T j T_j Tj 直接谓词依赖 T i T_i Ti

简单来说,一个事务 T i T_i Ti 执行了一个写操作,该写操作的结果被另一个事务使用谓词条件读取到了。或者说,一个事务 T i T_i Ti 执行了一个会影响另一个事务 T j T_j Tj 的谓词读的写操作时,事务 T i T_i Ti T j T_j Tj 存在共同操作的数据项或谓词。

注意,所有谓词读产生的版本集中的元组都会被访问,包括那些不匹配谓词的元组。 T j T_j Tj 实际读取的版本显示为正常的读取事件。版本集中的其他版本本质上是 “幽灵读(Ghost Reads)” 。例如,它们不可被谓词读观察到,却也为它们建立了读依赖。

谓词读依赖的规则是对谓词来说重要的是匹配或不匹配的元组集而不是它们的值。因此,在已经导致元组匹配(或不匹配) r j r_j rj(P: Vset(P)) 的所有事务中,使用更改 Vset(P) 的最新事务而不是在 Vset(P) 中建立版本的最新事务。该规则确保捕获谓词读的最小可能冲突。例如,思考如下历史:

H p r e d r e a d H_{predread}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独上西楼影三人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值