事务的基本概念
事务
事务:是一系列的数据库操作,是数据库应用程序的逻辑单位,即应用程序对数据库的操作都应该以事务的方式进行
事务是一个操作序列,这些操作要么都做,要么都不做
- BEGIN TRANSACTION:事务开始 begin transaction
- END TRANSACTION:事务结束 end transaction
- COMMIT:事务提交
- ROLLBACK:事务回滚
SQL中事务的开始与结束
SQL标准规定当一条SQL语句被执行,就隐式地开始了一个事务,SQL中的Commitwork和Rollback work语句之一会结束一个事务
- Commit work:提交当前事务。这意味着该事务所做的更新在数据库中永久保存。一但事务被提交后,一个新的事务自动开始。
- Rollback work:回滚当前事务。这意味着将撤销该事务对数据库的更新。
注意:如果事务已经执行了Commit work,就不能再用Rollback来撤销
事务的特性
- 原子性:事务的所有操作在数据库中要么都做要么都不做。
- 一致性:一个事务独立执行的结果,将保持数据的一致性,即数据不会因为事务的执行而遭受破坏。
- 隔离性:一个事务的执行不能被其他事务干扰。并发事务在执行过程中可能会对同一数据进行操作,这些事务的操作应该不会相互干扰,是相互隔离的。
- 持久性:一个事务一旦提交,它对数据库的改变必须是永久的,即使系统出现故障也是如此。
事务的状态
- 活动状态
- 事务的初始状态,事务执行时处于这个状态。
- 部分提交状态
- 当操作序列的最后一条语句执行后,事务就处于部分提交状态。这时,事务虽然已经完全执行,但由于实际输出可能还临时驻留在内存中,在事务成功完成前还有可能出现硬件故障,因此,部分提交状态并不等于事务成功执行。
- 失败状态
- 由于硬件或逻辑错误,使得事务不能继续正常执行,事务就进入了失败状态,处于失败状态的事务必须回滚。这样,事务就进入了中止状态。
- 中止状态
- 事务回滚并且数据库恢复到事务开始执行前的状态。
- 提交状态
- 当事务成功完成后,称事务处于提交状态。只有事务处于提交状态后,才能说事务已经提交
- BEGIN TRANSACTION:开始运行事务,使事务进入活动状态
- END TRANSACTION:说明事物中的所有读写操作都已完成,使事务进入部分提交状态,把事务的所有操作对数据库的影响存入数据库。
- COMMIT:标志事务已经成功地完成,事务中的所有操作对数据库的影响已经安全地存入数据库,事务进入提交状态,结束事务的运行。
- ABORT:标志事务进入失败状态,系统撤销事务中所有操作对数据库和其他事务的影响,结束事务的运行
数据库的并发控制
事务调度
串行调度
是指多个事务依次串行执行,且只有当一个事务的所有操作都执行完成才执行另一个事务的所有操作
并发调度
利用分时的方法同时处理多个事务
并发调度执行的结果与某一次串行调度执行的结果相同,则称这个并发调度是正确的
可恢复调度
指满足这样的条件的调度:当事务Tj要读事务Ti写的数据时,Ti事务必须要先于事务Tj提交。
并发操作带来的问题
并发操作带来的数据不一致性有三类
- 丢失修改
- 不可重复读
- 读脏数据
- 幻读也称幻影现象。事务T1读取数据后,事务T2执行插入或删除操作,使T1无法再现前一次读取结果
主要原因是事务的并发操作破坏了事务的隔离性
丢失修改
两个事务对同一个数据进行修改,导致事务A对数据库的修改被事务B的修改所覆盖
读脏数据
某事务读取的数据是其它事务修改后的值,但该修改后来又被撤销了
不可重复读
事务对同一数据进行两次读取的结果不同。原因是两次读取的间隙数据被另一事务修改了
并发调度的可串行性
- 多个事务的并发执行是正确的,当且仅当其结果与某一次序串行地执行它们的结果相同,称这种调度策略是可串行化的调度。
- 可串行性是并发事务正确性的准则。即:一个给定的并发调度,当且仅当它是可串行化的才认为是正确调度。
并发控制技术
并发事务如果对数据读写时不加以控制,会破坏事务的隔离性和一致性。为了保持事务的隔离性,系统必须对事务之间的相互作用加以控制,最典型的方式就是加锁
- 排它锁:简称X锁,也称为写锁,用于对数据进行写操作时进行锁定
- 如果事务T对数据A加上X锁后,就只允许事务T对数据A进行读取和修改
- 其他事务对数据A不能再加任何锁,从而也不能读取和修改数据A,直到事务T释放A上的锁
- 共享锁:简称S锁,也称为读锁,用于对数据进行读操作时进行锁定
- 如果事务T对数据A加上了S锁后,事务T就只能读数据A但不可以修改
- 其他事务可以再对数据A加S锁来读取
- 只要数据A上有了S锁,任何事务都只能再对其加S锁读取而不能加X锁修改
封锁协议
- 一级封锁协议
- 事务T在修改数据A之前必须先对其加X锁,直到事务结束才释放X锁
- 解决了丢失修改的问题
- 二级封锁协议
- 一级封锁协议加上事务T在读取数据A之前必须对其加上S锁,读完后即可释放S锁
- 解决了读脏数据的问题
- 三级封锁协议
- 是一级封锁协议加上事务T在读取数据A之前必须对其加上S锁,直到事务结束才释放S锁
- 解决了不可重复读的问题
两段锁协议
两段锁协议(2PL):是指同一事务对任何数据进行读写之前必须对该数据加锁;在释放一个封锁之后,该事务不再申请和获得任何其他封锁
- 所谓“两段”的含义是:事务分为两个阶段。
- 第一阶段是获得封锁,也称为扩展阶段。
- 第二阶段是释放封锁,也称为收缩阶段
eg.T1:Slock A…Slock B…Xlock C…Unlock B…Unlock A…Unlock C
- 遵循两段锁协议,一定是可串行化的;不遵循两段锁协议,可能是可串行化的,也可能不是
- 采用两段锁协议也有可能产生死锁
事务的隔离级别
- 事务的隔离级别并不是越高越好
- 隔离级别越高,数据一致性越强,系统代价增高
在SQL标准中给出了事务的4类隔离级别,由低到高依次如下:
- READ UNCOMMITTED(读未提交):允许一个事务可以读取另一个未提交事务正在修改的数据
- READ COMMITTED(读已提交):只允许一个事务读其他事务已提交的数据
- REPEATABLE READ(可重复读):一个事务开始读取数据后,其他事务就不能再对该数据执行更新(UPDATE)操作了
- SERIALIZABLE(可串行化):最高级别,在该级别下,事务的执行顺序是可串行化的
数据库的备份与恢复
数据库系统故障的种类
- 事务故障
- 是由于程序执行错误而引起事务非预期的、异常终止的故障。通常有如下两类错误引起事务执行失败
- 逻辑错误:如非法输入、找不到数据、溢出、超出资源限制等原因引起的事务执行失败
- 系统错误:系统进入一种不良状态(如死锁),导致事务无法继续执行
- 是由于程序执行错误而引起事务非预期的、异常终止的故障。通常有如下两类错误引起事务执行失败
- 系统故障
- 是指硬件故障、软件(如DBMS、OS或应用程序)漏洞的影响,导致丢失了内存中的信息,影响正在执行的事务,但未破坏存储在外存上的信息
- 介质故障
- 是指数据库的存储介质发生故障,如磁盘损坏、瞬间强磁场干扰等。这种故障直接破坏了数据库,会影响到所有正在读取这部分数据的事务
数据库备份
数据转储是将数据库自制到另一个磁盘或磁带上保存起来的过程,又称为数据备份
- 静态转储和动态转储
- 静态转储是指在转储期间不允许对数据库进行任何存取、修改操作
- 动态转储是在转储期间允许对数据库进行存取、修改操作,因此,转储和用户事务可并发执行
- 海量转储和增量转储
- 海量转储是指每次转储全部数据
- 增量转储是指每次只转储上次转储后更新过的数据
- 日志文件
- 在事务处理的过程中,DBMS把事务开始、事务结束以及对数据库的插入、删除和修改的每一次操作写入日志文件
- 数据库镜像
- 为了避免磁盘介质出现故障影响数据库的可用性,许多DBMS提供数据库镜像功能用于数据库恢复
数据恢复
要使数据库在发生故障后能够恢复,必须建立冗余数据,在故障发生后利用这些冗余数据实施数据库恢笔,常用的是数据转储和日志文件
故障恢复的两个操作
- UNDO:撤销事务。将未完成的事务撤销,使数据库恢复到事务执行前的正确状态
- 反向扫描日志文件(由后向前扫描),查找事务的更新操作
- 对该事务的更新操作执行逆操作,用日志文件记录中
- 更新前的值写入数据库
- 插入的记录从数据库中删除
- 删除的记录重新插入数据库中
- REDO:重做事务。将已提交的事务重新执行
- 从事务的开始标志起,正向扫描日志文件
- 重新执行日志文件登记的该事务对数据库的所有操作
- 从事务的开始标志起,正向扫描日志文件
故障恢复策略
- 事务故障的恢复
- 事务故障是事务在运行至正常终止点(COMMIT或ROLLBACK)前终止
- 日志文件只有该事务的开始标识而没有结束标识
- 对这类故障的恢复通常是通过撤销(UNDO)产生故障的事务,使数据库恢复到该事务执行前的正确状态来完成的
- 系统故障的恢复
- 系统故障会使数据库的数据不一致
- 一是未完成的事务对数据库的更新可能已经写入数据库
- 二是已提交的事务对数据库的更新可能还在缓冲区没来得及写入数据库
- 撤销故障发生时未完成的事务(UNDO)
- 重做已经提交的事务(REDO)
- 介质故障
- 介质故障时数据库遭到破坏,需要重装数据库,一般需要DBA的参与
- 装载故障前最近一次的备份和故障前的日志文件副本,再按照系统故障的恢复过程执行撤销(UNDO)和重做(REDO)来恢复
具有检查点的恢复技术
检查点(CHECKPOINT)出现的原因:
- 搜索整个日志将耗费大量的时间
- 很多需要重做处理的事务实际上已经将其更新操作结果写到了数据库中,而恢复子系统又重新执行了这些操作,浪费了大量时间
检查点记录的内容:
- 建立检查点时刻所有正在执行的事务清单
- 这些事务最近一个日志记录的地址
系统使用检查点方法进行恢复的步骤是:
- 故障发生(故障点),找到最近的一个检查点
- 寻找故障发生前所有的活动事务
- 将检查点前结束的事务不做任何处理
- 将故障点前完成的事务做REDO处理
- 将故障点前未完成的事务做UNDO处理