事务

概念

用户定义的一个不可分割的数据库操作序列。这些操作要么全做,要么不做。

一个事务可以是一条SQL语句,可以实一组SQL语句,也可以是整个程序。事务的开始和结束可以由用户显式控制,若用户未显式定义事务,则由DBMS按默认规定自动划分事务。

事务是恢复和并发控制的基本单位。

事务的定义

事务的开始

1
BEGIN TRANSACTION; /*事务开始*/

事务的结束

提交或者回滚。

1
2
COMMIT;   /*奖事务中的所有对数据库的更新写回到磁盘上的物理数据库中*/
ROLLBACK;   /*系统将所有已完成的操作全部撤销,回滚到事务开始时的状态*/

ACID属性

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持续性(Durability)/永久性(Permanence)

其中一致性原子性密切相关,一般情况下,事务的原子性不正常(事务被迫中断),就会导致不一致性状态。

隔离性是指一个事务的执行不能被其他食物干扰。即一个事务的内部操作及使用的数据对其他并发事务是隔离的,并发执行的各个十五之间不能相互干扰。

事务管理

保证事务的ACID属性是事务管理的重要任务。

事务ACID属性可能遭到破坏的因素:

  • 多个事务并行运行时,不同事务的操作交叉进行
  • 事务在运行过程中被强行停止

并发控制

背景

多处理机系统中,每个处理及可以运行一个事务,多个处理及可以同时运行多个事务,实现多个事务真正的并行运行。这种并行执行方式称为同时并发运行(simultaneous concurrency)。并发操作可能会破坏数据的不一致性:

  • 丢失修改(lost update)

  • 不可重复读(non-repeatable read)

其中,不可重复读包括并发事务的修改删除插入操作。事务T2T1读取某些数据库后删除或者插入一些记录,导致T1重复读取数据发现数据不一致,也成为幻影(phantom row)现象

  • 读脏数据(dirty read)

产生上述三类数据不一致性的主要原因是并发操作破坏了事务的隔离性。并发操作就是要用正确的方式调度并发操作,是一个用户事务的执行不受其他事务的干扰,从而避免造成数据的不一致性。当然,为了加强数据的一致性而调度并发操作,通常会增大系统的开销,最好就是做到一致性要求内系统开销最小。

技术

并发控制的主要技术有:

  • 封锁(locking)
  • 时间戳(timestamp)
  • 乐观控制法(optimistic scheduler)
  • 多版本并发控制(multi-version concurrency control, MVCC)

封锁

锁的种类

  • 排他锁(exclusive locks),简称X锁,即写锁
  • 共享锁(share locks),简称S锁,即读锁

封锁类型的相容矩阵

封锁协议

不同级别的封锁协议的一致性保证

使用封锁机制解决三种数据不一致性的示例

上述三级协议的主要区别在于什么操作需要申请封锁,以及何时释放锁(即持锁时间)。不同的封锁协议使事务达到的一致性级别是不同的,封锁协议级别越高,一致性程度越高。

活锁和死锁

活锁死锁示例

活锁

如果事务T1封锁了数据R,事务T2又请求封锁R,于是T2等待;T3也请求封锁R,当T1释放了R上的封锁之后系统首先批准了T3的请求,T2仍然等待;然后T4又请求封锁R,当T3释放了R上的封锁之后系统又批准了T4的请求……T2有可能永远等待,形成活锁。

解决活锁的简单方法

先来先服务

死锁

如果事务T1封锁了数据R1, T2封锁了数据R2,然后T1又请求封锁R2,因T2已封锁了R2,于是T1等待T2释放R2上的锁;接着T2又申请封锁R1,因T1已封锁了R1,T2也能等待T1释放R1上的锁。这样就出现了T1在等待T2,而T2又在等待T1的局面,T1T2两个事务永远不能结束,形成死锁。

解决死锁的简单方法

1.预防

  • 一次封锁法:要求每个事务必须一次将所有要使用的数据全部加锁(扩大封锁范围会降低系统并发度)
  • 顺序封锁法:预先对数据对象规定一个封锁顺序(数据随时变化,维护难度大;事先规定的顺序难以实际施加封锁)

2.诊断与解除

  • 超时法:以超时为标志判定死锁(容易误判;时限设置太长不容易发现思索)
  • 等待图法:并发控制子系统周期性生成十五等待图,并进行检测,如果图中存在回路则表示出现死锁。

通常选择一个处理死锁代价最小的事务将其撤销,释放此事务的所有锁,使得其他事务得以继续运行下去,同时对撤销的事务所执行的数据修改操作必须加以恢复。