数据库概论.陈立军.06.事务

事务

事务概念

  • transaction(交易)
  • 交易的核心:完整性
  • Jim Gray:在事务处理方面做出巨大的贡献
    • 书籍:transaction processing: concept and techniques
  • commitment
    • 事务包含了很多操作,commitment 指把所有的操作完整的提交到数据库上
    • It's like bacon and eggs. The chicken participants. The pig commited.
  • 一致性条件
    • 银行转账,两个账户的总和在转账前后保持不变
    • 存在两个操作,转出账户余额减去转账金额,转入账户余额加上转账金额
      • 必须保证这组操作的整体性

事务定义

  • 事务是由一系列操作序列构成的执行单元,这些操作要么都做,要么都不做,是一个不可分割的工作单位
  • \({\color{red}\mathrm{All\;or\;None}}\)

事务中的数据访问原语

  • read(X):从数据库传送数据项 X 到事务的工作区中
    • 从数据缓冲区读出来
  • write(X):从事务的工作区中将数据项 X 写回数据库

转账事务的原语表达

  • 事务 T 从 A 帐户过户 50 到 B 帐户

\[ \begin{aligned} &read(A);\\ &A := A –50;\\ &write(A);\\ &read(B);\\ &B := B + 50;\\ &write(B);\\ \end{aligned} \]

  • 电子商务:事务是现代信息系统的基石

SQL中事务的定义

  • 事务以 Begin transaction 开始,以 Commit transaction 或 Rollback transaction 结束
    • Commit transaction 表示提交事务正常结束
    • Rollback transaction 表示事务非正常结束,撤消事务已做的操作,回滚到事务开始时状态
  • 具体的结束方式,通过加入某些条件判断
  • terminate 与 abort
    • Terminate:终止(中性)
    • Abort:中止(失败,需要 rollback)

事务执行模式

显式事务

  • 以 begin transaction 开始,以 commit 或 rollback 结束

隐含事务

  • 事务自动开始,直到遇到 commit 或 rollback 时结束
  • set implicit_transactions{ ON | OFF }

自动事务

  • 每个数据操作语句作为一个事务
  • update SC set GRADE = GRADE+15

事务中的错误检查

  • GRADE 约束小于等于100,现在数据库中有两个 GRADE (80, 90)
  • 事务 update SC set GRADE = GRADE+15 操作的结果
    • (80,90),事务出错,整个回滚
  • 如下事务操作的结果
    • (85, 95)
      • 不做设置的前提下,会将第一个操作提交
    • 设置 set XACT_ABORT ON 之后结果为 (80,90)
1
2
3
4
5
6
7
8
Begin tran
Update SC
Set grade = grade+5
--没有违反 grade<=100 约束
Update SC
Set grade = grade+20
--违反了 grade<=100 约束
Commit tran
  • 如下事务操作的结果
    • (80, 90)
    • rollback 把整个事务回滚
1
2
3
4
5
6
7
8
Begin tran
Update SC
Set grade = grade+5
Update SC
Set grade = grade+20
If @@error<>0 -- 全局变量, 上一行语句操作设置
rollback tran
Commit tran

事务基本特性ACID

  • \(\mathrm{ACID:Atomicity\;Consistency\;Isolation\;Durability}\)

原子性(Atomicity)

  • 事务中包含的所有操作要么全做,要么全不做
  • 原子性由恢复机制实现
    • 通过日志进行恢复

一致性(Consistency)

  • 事务的隔离执行必须保证数据库的一致性
  • 事务开始前,数据库处于一致性的状态;事务结束后,数据库必须仍处于一致性状态
  • 数据库的一致性状态由用户来负责
  • 如银行转帐,转帐前后两个帐户金额之和应保持不变
    • 意大利香肠术,Salami technique
    • 偷小钱的盗窃术被称为意大利香肠术(意大利香肠切得很薄,偷一片看不出来)

隔离性(Isolation)

  • 系统必须保证事务不受其它并发执行事务的影响
  • 对任何一对事务 T1,T2,在 T1 看来,T2 要么在 T1 开始之前已经结束,要么在 T1 完成之后再开始执行
    • 等价于串行执行的效果
  • 隔离性通过并发控制机制实现

持久性(Durability)

  • 一个事务一旦提交之后,它对数据库的影响必须是永久的
  • 系统发生故障不能改变事务的持久性
    • 系统的抗故障能力
    • 大企业的数据,备份,多个物理实体(物理上相隔较远,避免自然灾害的影响)
  • 持久性通过恢复机制实现
  • 持久性:将来总能够再现这个事务

事务生命周期图

  • 部分提交状态:事务的所有操作都做完了
  • 一个事务的所有操作都做完了,并不意味着一定能成功提交,因为要保证持久性
    • 数据库在做完事务的所有操作之后,在向程序客户端发送成功消息之前,把这个事务对应的日志记录从内存写入磁盘
    • 如果系统崩溃,内存中的数据丢失了,可以从日志记录恢复数据

事务调度

  • 事务的执行顺序称为一个调度,表示事务的指令在系统中执行的时间顺序
  • 一组事务的调度必须保证
    • 包含了所有事务的操作指令
    • 一个事务中指令的顺序必须保持不变

事务调度例子

  • \(T_1:i_{11},i_{12},T_2:i_{21},i_{22}\)
    • \(S_1:i_{11},i_{12},i_{21}\)
    • \(S_2:i_{11},i_{22},i_{12},i_{21}\)
    • \(S_2:i_{11},i_{21},i_{12},i_{22}\)
  • \(S_1,S_2\) 不是一个调度,\(S_3\) 是一个调度

并行与串行

串行调度

  • 在串行调度中,属于同一事务的指令紧挨在一起
  • 串行调度总是正确的
  • 对于有 \(n\)个事务的事务组,可以有 \(n!\) 个有效调度

并行调度

  • 在并行调度中,来自不同事务的指令可以交叉执行
  • 当并行调度等价于某个串行调度时,则称它是正确的
  • \(n\) 个事务,\(t_i\)\(k_i\) 条指令,则可能的并发调度有多少个
    • \(\dfrac{(\sum k_i)!}{\prod(k_i!)}\)
    • 事务内有序

并行和串行的比较

基本比较
  • 并行事务有可能破坏数据库的一致性
  • 串行事务效率低
并行的优点
  • 一个事务由不同的步骤组成,所涉及的系统资源也不同。这些步骤可以并发执行,提高系统的吞吐量
  • 系统中存在着周期不等的各种事务,串行会导致难于预测的时延。如果各个事务所涉及的是数据库的不同部分,采用并发会减少平均响应时间

事务调度例子

  • 两个转账事务
    • \(T_1\):从 A 过户 50 到 B
    • \(T_2\):从 A 过户存款的 10% 到 B

\[ \begin{aligned} &T1\\ &read(A);\\ &A := A −50;\\ &write(A);\\ &read(B);\\ &B := B + 50;\\ &write(B);\\\\ &T2\\ &read(A);\\ &temp := A*0.1;\\ &A := A −temp;\\ &write(A);\\ &read(B);\\ &B := B + temp;\\ &write(B);\\ \end{aligned} \]

  • 开始状态:A=1000,B=2000,A+B=3000

串行调度1

  • \(T_1,T_2\)
  • 结束状态:A=855,B=2145,A+B=3000

串行调度2

  • \(T_2,T_1\)
  • 结束状态:A=850,B=2150,A+B=3000
  • 串行调度可能会有不同的结果,但是都满足一致性,都是正确的

并行调度1

\[ \begin{aligned} &T1:\;read(A);\\ &T1:\;A := A −50;\\ &T1:\;write(A);\\ &T2:\;read(A);\\ &T2:\;temp := A*0.1;\\ &T2:\;A := A −temp;\\ &T2:\;write(A);\\ &T1:\;read(B);\\ &T1:\;B := B + 50;\\ &T1:\;write(B);\\ &T2:\;read(B);\\ &T2:\;B := B + temp;\\ &T2:\;write(B);\\ \end{aligned} \]

  • 需要保证操作 4 在操作 3 之后,否则是错误的
  • 结束状态:A=855,B=2145,A+B=3000
  • 等价于串行调度 \(T_1,T_2\)

并行调度2

\[ \begin{aligned} &T1:\;read(A);\\ &T1:\;A := A −50;\\ &T2:\;read(A);\\ &T1:\;write(A);\\ &T2:\;temp := A*0.1;\\ &T2:\;A := A −temp;\\ &T2:\;write(A);\\ &T1:\;read(B);\\ &T1:\;B := B + 50;\\ &T1:\;write(B);\\ &T2:\;read(B);\\ &T2:\;B := B + temp;\\ &T2:\;write(B);\\ \end{aligned} \]

  • 错误的
  • 结束状态:A=900,B=2150,A+B=3050

可恢复调度

  • 事务的恢复
    • 一个事务失败了,应该能够撤消该事务对数据库的影响
    • 如果有其它事务读取了失败事务写入的数据,则该事务应该撤消
  • 一个不可恢复调度的例子
T1 T2
read(A)
write(A)
read(A)
commit
read(B)
rollback
  • 回滚 T1 的时候,T2 已经提交了,如果 T2 被撤销了,那么就违反了事务的持久性
    • 在真实场景中, 会向 T2 发起一个补偿事务

可恢复调度定义

  • 对于每对事务 T1 与 T2,如果 T2 读取了 T1 所写的数据,则 T1 必须先于 T2 提交

无级联调度

  • 级联调度
    • 由于一个事务故障而导致一系列事务回滚
  • 级联调度例子
T1 T2 T3
read(A)
read(B)
write(B)
read(A)
write(A)
read(A)
rollback

无级联调度定义

  • 对于每对事务 T1 与 T2,如果 T2 读取了 T1 所写的数据,则 T1 必须在 T2 读取之前提交
  • 无级联调度必是可恢复调度
    • 要求比可恢复调度更加严格

并发调度中的不一致现象

丢失修改

  • 两个事务 T1 和 T2 读入同一数据并修改,T1 提交的结果破坏了 T2 提交的结果,导致 T2 的修改丢失
  • 一个例子:售票窗口
    • 下面的操作只反映了售票窗口 T1 的结果,但是没有反应售票窗口 T2 的结果

  • 写 —— 写不一致

读脏数据

  • 事务 T1 修改某一数据,并将其写回磁盘,事务 T2 读取同一数据后,T1 由于某种原因被撤消,这时 T1 已修改过的数据恢复原值,T2 读到的数据与数据库中数据不一致,则 T2 读到的数据就是脏数据
  • 一个例子

  • 写 —— 读不一致

不能重复读

  • 事务 T2 读取某一数据后,事务 T1 对其做了修改,当 T2 再次读取该数据时,得到与前次不同的值

  • 读 —— 写不一致
  • 发生概率比读脏数据小
  • 例子
    • r1(list) r2(list) w2(list) r2(count) w2(count) commit(t2) r1(count)
    • r1(list) 和 r1(count) 不一致

发生幻象(Phantom)

  • 事务 T2 按一定条件读取了某些数据后,事务 T1 插入了一些满足这些条件的数据,当 T2 再次按相同条件读取数据时,发现多了一些记录

  • 不可重复读是指对同一条记录出现不一致情况,幻象指的是多出来或者少掉某些记录
    • 防止幻象更难
    • 例如
      • 防范不可重复读只需要将原来在数据库中的数据锁住
      • 防范幻象则比较难,怎么处理新来的数据