数据库杂谈(九)——事务管理

文章目录

  • 9 事务管理
    • 9.1 恢复机制
    • 9.2 事务和日志
      • 9.2.1 事务
      • 9.2.2 运行记录的结构
        • 9.2.2.1 活动事务表
        • 9.2.2.2 提交事务表
        • 9.2.2.3 日志
      • 9.2.3 提交规则和先记后写规则
        • 9.2.3.1 提交规则
        • 9.2.3.2 先记后写规则
    • 9.3 更新策略以及故障后的恢复

9 事务管理

9.1 恢复机制

数据对一个单位是非常重要的。也就是说,数据库的失效常常导致一个单位的瘫痪。为此,对数据库出现的故障有备选的方案去处理是非常重要的。

数据库出现故障时处理的重点就突出两个字:防、治

数据库出现故障的时候,如果是防,我们就尽可能提高系统的可靠性;如果防不住我们就治,在数据库系统发生故障后,把数据库恢复到之前的状态。一般来说,我们做第一手的准备不足以保证数据库数据的安全,比如突然停电,这种东西谁都防不住,所以通常在第一手准备的情况下,我们会去做第二手准备,而第二手准备,就是我们讨论的重点:恢复技术。

数据的恢复机制必须要求以下两点:

一、数据冗余

硬件和软件出现故障,就会导致运行出现差错,也就会导致数据库失效。故障是前因,差错是现象,失效是后果。为了恢复失效后果,我们必须留有后备的副本以备不时之需,这样来看的话,备份就会导致数据冗余是必需的。

这里的冗余和数据库设计的冗余不一样,那里的冗余指的是数据库结构为了追求三范式,而有些地方不合理造成的冗余;而我们上面说的冗余是留有数据做备份。

二、自动检测故障

要能够检测出故障,不能出现故障了还没有停下来,稀里糊涂的继续操作下去。

说完数据恢复必要的元素,我们来讲讲恢复技术有哪些。大体来说一般归为以下三类。

单纯以后备副本为基础的恢复技术(周期性转储)

这个是从文件系统继承过来的恢复技术。这里要继续讲下去又得讲一下磁带了。

磁带就相当于小时候的录音带,你甚至可以理解为他是读卡器,他是一种可以脱机的存储设备,但是容易损坏。

所以使用以后备副本为基础的恢复技术时,我们会把磁盘上的数据库周期性转储到磁带上,当然你也可以刻在光盘上。由于磁带可以脱机存放,可以不受系统故障的影响,所以存在磁带的那部分数据库副本我们叫后备副本

那你可以试想,数据库如此庞大,假如真的让你那个类似于U盘一样的东西去拷贝,拷贝一次需要多久?而且在拷贝过程中数据库不能改变,相当于冻结了数据库,暂停其运作;所以在取后备副本的时候由于时间问题,我们不能频繁的取,一般周末夜间数据库空闲的时刻才会去操作。

但是这样一来你就会发现一个问题:假如我取后备副本的周期过长,那就会导致假如在上一次取后备副本到数据库突然故障这段期间我做了大量的更新的话,那么就会导致这些操作全部白干。

所以,我们想到了提高这个恢复技术的办法,也就是增量存储。这实际上是周期性转储方法的变种。一般来说,数据库不会改动整个结构,只会改动其中一小部分,我们可以把那一小部分所对应的物理块拿出来高频(也就是周期很短)地转储,其他的物理块可以很久才转储一次,这样的话,一旦发生故障,马上就能恢复最近更新的那一部分的物理块,损失度大幅下降。

海量转储增量转储
每次转储全部数据库只转储上次转储更新过的数据

对于海量存储和增量存储来说各有好坏:

  • 从恢复角度看,使用海量转储得到的后备副本进行恢复往往更方便
  • 如果数据库很大,事务处理又十分频繁,则增量转储更有效
img

由于这种方法实现起来很简单,所以在文件系统使用得很多,但是在数据库系统中只用于小型的和不重要的数据库系统。

以后备副本和运行记录(log或者journal)为基础的恢复技术

这种技术是企业里面用的最多的技术。

在SQLserver中,我们能看到建数据库的时候我们还会建一个日志文件log,这里就派生用场了。日志实际上就是一个流水账,我们也叫他是一个运行记录,记录你所有操作的流水;其中运行记录里面记了两样东西,一种是前像,一种是后像

前像(也就是老的数据,老值)(Before image,简称BI)

如果数据库被事务做了一次更新,那么我们就可以利用还没更新前数据库的数据涉及的物理块来恢复更新前的状态,也就是撤销更新,这种操作我们在恢复技术里叫做撤销(英文简称undo)。

后像(也就是新的数据,新值)(After image,简称AI)

同样的,我们更新后也有更新后数据涉及的物理块,如果更新的数据突然没了,我们可以根据这个物理块把更新的数据恢复到更新后的状态。这就是重做(英文简称redo)。

上面可能听的有点蒙,这么说吧,我们有两个备份——前像和后像。其中前像就是一面通往过去的魔镜,后像就是一个通往未来的过程,终点是更新结束。如果你更新到一半卡住了,说你更新了吧,你没更新完,说你没更新,你又开始更新了,那你此时就可以根据过去的魔镜回到过去。如果你更新完成了,但是更新了啥你却丢了。那这个时候你就可以利用后像重新走一次更新过程。

就拿修改表数据的相关操作来说,日志记录以下情况:

for update op:BI AIinsert op:—— AIdelete op:BI ——

事务状态:记录每个事务的状态,方便在恢复的时候做不同的处理。

每个事务在提交的时候面临两种结局:

第一种是提交了才结束,这标志着事务成功地执行了,只有在事务提交后,事务对数据的影响才能被其他事务访问。

第二种是由于事务本身或者外部的原因,事务失败,也就是说这时候可能事务只做了一半,要继续做的时候事务出问题终止了,这时候为了消除那做了一半的影响,我们会对其做出卷回

如果是数据库失效了,可以取出后备副本,然后根据运行的记录,如果没提交就将前像卷回,这叫向后恢复。如果事务已经被提交了,但是提交前和提交后中间添加的数据没了,那我们必要时用后像重做,这叫向前恢复

基于多副本的恢复技术

如果系统中有多个数据库副本,而且这些副本具有独立的失效模式,则可利用这些副本相互备份,用于恢复。所谓的独立失效模式是指各个副本不会因为故障而一起失效。为了尽可能的创建这种环境,各副本的支撑环境要尽可能地独立,比如不要共用电源、磁盘、控制器和CPU等等,反正就是尽可能不要共用东西就对了。这种技术在分布式数据库用的比较多。

由于现在硬件价格下降,很多人都能买得起磁盘,所以在一些可靠性要求高的系统中,常常采用镜像磁盘技术,镜像磁盘技术为了使失效模式独立,两个磁盘系统有各自的控制器和cpu,但彼此可以相互切换。他的原理如下

  • DBMS自动把整个数据库或其中的关键数据复制到另一个磁盘上

  • DBMS自动保证镜像数据与主数据库的一致性,每当主数据库更新时,DBMS自动把更新后的数据复制过去,如图:

img

出现介质故障时

  1. 可由镜像磁盘继续提供使用
  2. 同时DBMS自动利用镜像磁盘数据进行数据库的恢复
  3. 不需要关闭系统和重装数据库副本

img

没有出现故障时,镜像磁盘可用于并发操作,一个用户对数据加排他锁修改数据,其他用户可以读镜像数据库上的数据,而不必等待该用户释放锁。

9.2 事务和日志

我们在这一讲谈到了多次事务,那事务(transaction)到底是啥呀。

9.2.1 事务

一个事务是一个完整的业务逻辑单元,不可再分。

比如:银行账户转账,从A账户向B账户转账10000,需要执行两条Update语句。

update t_act set balance = balance -10000 where actno = 'act_001';update t_act set balance = balance + 10000 where actno = 'act_002';

以上这个过程是一起的,如果不一起,就会导致转账这件事失败。也就是说,以上两条DML语句必须同时成功,或者同时失败,不允许出现一条成功,一条失败。

要想保证以上的两条DML语句同时成功或者同时失败,那么就需要使用数据库的“事务机制”。

需要注意的是,和事务相关的SQL语句只有DML语句,因为它们包含的添加、删除、更新语句都是和数据库表当中的“数据”相关的。事务的存在是为了保证数据的完整性,安全性。

有人会发出疑问:假设所有的事务都能使用一条DML语句搞定,还需要事务机制吗?如果真的出现上述情况,那么确实不需要事务。但实际情况不是这样的,通常一个事务需要多条DML语句共同联合完成。

事务可以保证多个操作原子性,要么全成功,要么全失败。对于数据库来说事务保证批量的DML要么全成功,要么全失败。综上所述,事务具有四个特征:ACID。

  • A原子性:整个事务中的所有操作,必须作为一个单元全部完成(或者全部取消),即:要么不做,要么全做

  • C一致性:在事务开始之前和结束之后,数据库都保持一致状态

  • I隔离性:一个事务不会影响其他事务的运行

  • D持久性:持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功的结束。也就是说,一个成功执行的事务对数据库的影响是持久的,即使数据库因故障而受到破坏,DBMS也应该能够恢复

我们来看看一个事务的案例:

Begin transactionread AA:=A-sif A<0 then Display "insufficient fund"Rollback /*undo and terminate*/else B:=B+sDisplay "transfer complete"Commit /*commit the update and terminate*/Rollback --abnormal termination
Commit --normal termination

假如现在做一个银行转账系统,A给B转了s元,如果A余额不足,那么就会提示:insufficient fund(余额不足),然后把A余额-s元的这个操作回滚。

如果余额足够,那么A-s,B+s,然后提示转账成功,然后事务结束,利用Commit提交事务。

9.2.2 运行记录的结构

9.2.2.1 活动事务表

记录运行记录的有多个结构,与操作系统类似,操作系统中有记录进程的进程块PCB,对于事务来说则有标识符(Transaction Identifier,TID)。对于所有正在执行,尚未提交的事务,其身上的标识符都会在活动事务表(Active Transacion list,ALT)中占有一条元组。活动事务表会给这些事务贴上正在执行、尚未提交的标识符。

9.2.2.2 提交事务表

提交事务表(Committed Transaction list,CTL)记录所有已经提交的事务的标识符。

当你把一个事务要提交了,那活动事务表会把TID交给提交事务表,然后在活动事务表中把该TID删除。但是,这两者顺序是不可颠倒的,如果颠倒,万一停电,就会导致TID刚在活动事务表中删除,然后在添加进提交事务表的那一刻由于故障没有任何记录。

9.2.2.3 日志

对于数据库来说,日志(log)一般记录了操作的流水记录。其一般存储在非挥发存储器(非易失存储器)中。

存储器一般分为主存和辅存。

主存通常指随机访问存储器(RAM),一般分为两种:一种是易失性随机访问存储器,如RAM(磁芯存储器)、CMOS;另外一种是非易失性随机访问存储器,它们和RAM不同,遇到突然的外界因素不会丢失其内容。例如:ROM(只读存储器)、EEPROM(电可擦除可编程ROM)、闪存。

日志主要包含TID,前像文件和后像文件。具体结构如下:

image-20211003102941693

其中前像文件中的BID记录的是物理块的地址,空白部分记录的是正在更新事务的老值,这一个矩形就相当于一个物理块,前像文件相当于一个堆文件,有很多物理块堆叠而成,如果一个关系需要卷回,就可以从前像文件中找出该事务的所有前像块,然后把它们全部写入由于故障被破坏的关系的对应块中从而消除该事务对数据库所产生的影响。同理,后像文件也和前像文件的结构一样。

在每个日志中都应该记录前像文件和后像文件,以方便供以恢复使用。

9.2.3 提交规则和先记后写规则

9.2.3.1 提交规则

后像(新值)必须在事务提交前写入非挥发存储器中,不能放在内存中,因为内存会消失。

也就是说,后像可以放数据库也可以放日志中(前面说过日志也是一个非挥发存储器);万一这时候故障,即使没有放数据库,我们也可以利用日志中的后像文件中的后像重做;如果这时候有其他事务要访问这些数据,由于更新的内容已经保存在后像文件里面了,也可能在缓冲区中(因为后像文件是由多个物理块组成的),所以其他事务仍然可以去缓冲区或者后像文件找哪些更新后的内容。

9.2.3.2 先记后写规则

如果后像在事务提交前写入了数据库,那必须把前像首先记入运行记录。

这句话可能有点抽象,我们举个例子。假如我现在在做笔记,如果我没有保存以前写的旧笔记,直接把旧笔记撕了,然后直接写新笔记,这时候一旦突然断电,那就有可能新笔记和老笔记都没了。先记后写规则就是为了防备这一点。

9.3 更新策略以及故障后的恢复

更新操作无非就是undo或redo。需要注意的是,undo操作和redo操作具有幂等性。

举个例子:假如在编程中,我们设x = 10,后面又写了一条x = 20,那么就能把x = 10覆盖掉,其中后像20,前像10,但是后像20覆盖前像10的时候,不管覆盖多少次都是20,这就是幂等性,即做多次操作和一次操作的效果是等价的。

更新操作并不是上来就无脑搞,是有一定策略的。目前理论上的更新策略有以下几种。

后像在事务提交前已经完全写入数据库(没人采用)

策略具体步骤如下:

  1. TID→ATL

  2. BI→log

  3. AI→DB,log

  4. TID→CTL

  5. 从ATL删除TID

在每个数据库系统里总会有这么个模块——重启动模块,不同数据库系统叫法可能不同;他的作用是在重启动数据库系统后,检查上一次退出是否正常退出。

在用重启动模块检查数据库系统时,会出现下列三种情况:

ATLCTL事务所处状态恢复措施
-1已经完成,但4没有完成①若BI已经写入log则undo,否则无需undo ②从ATL删除TID
4执行完成从ATL删除TID
-5执行完成无需处理
  • 如果ATL里有而CTL没有,说明在提交阶段出问题了,那么系统会自动去undo收回那些事务。
  • 如果ATL有,CTL也有,说明事务已经提交,但是ATL删除TID的时候出问题了,那么系统就会去删除TID。
  • 如果ATL没有,CTL有,说明过程执行没有出现差错,事务提交完毕。

后像在事务提交后才写入数据库(目前主流)

策略具体步骤如下:

  1. TID→ATL

  2. AI→log

  3. TID→CTL

  4. AI→DB

  5. 从ATL删除TID

TID提交ATL说明执行为提交,这时候由于后像没有在事务提交前写入数据库,所以不必记录前像,这时把后像记到日志,然后TID提交给CTL,这时候确定后像提交了,然后再把AI给DB,然后在ATL删除TID。

在用重启动模块检查数据库系统时,会出现下列三种情况:

ATLCTL事务所处状态恢复措施
-1已经完成,但4没有完成①从ATL删除TID
3已经完成,但5没有完成①redo ②从ATL删除TID
-5执行完成无需处理
  • 如果检查时发现ATL有TID而CTL没有,说明提交CTL过程出错,这时候由于还未在其他地方做出任何操作,无须undo,只需在ATL删除TID即可。

  • 如果检查ATL和CTL都有TID,那么说明ATL删除TID出错,甚至AI搬到DB的阶段搬到一般故障了也有可能,所以这时候需要重新开始搬,即redo,然后在ATL里删除TID。由于幂等性,即使你前面搬到一半,现在redo重新搬也不会搬多。

  • 如果ATL没有而CTL有说明过程结束了,无须任何操作。

后像在事务提交前后写入数据库(现在过时了)

策略思想:在第二个策略的基础上,人们想了一个办法,同样的不将后像在事务提交前急忙写入数据库,而是创建一个后台进程,当数据库空闲的时候后台进程将其唤醒,开始把后像搬到数据库,一旦数据库忙起来了,就暂停搬运。

  1. TID→ATL

  2. AI,BI→log

  3. AI→DB(部分写入)

  4. TID→CTL

  5. AI→DB(继续完成)

  6. 从ATL删除TID

在用重启动模块检查数据库系统时,会出现下列三种情况:

ATLCTL事务所处状态恢复措施
-1已经完成,但4没有完成①若BI已经写入log则undo,否则无需undo ②从ATL删除TID
4已经完成,但6没有完成①redo ②从ATL删除TID
-6执行完成无需处理
  • 如果ATL有TID而CTL没有,说明BI可能有一部分在搬到数据库了,这时候需要做undo。

  • 如果ATL有,CTL也有,说明AI可能搬到一半,ATL还没删除TID,所以为了继续搬完,我们要根据前像做redo,搬完后在ATL删除TID。

  • 如果ATL和CTL都有,说明过程全部执行完毕,无须操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/398586.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS邮件相关

转载于:https://blog.51cto.com/8465917/1758775

MySql 错误 Err [Imp] 1153 - Got a packet bigger than 'max_allowed_packet' bytes

今天在用Navicat导入SQL文件时报错&#xff1a;MySql 错误 Err [Imp] 1153 - Got a packet bigger than max_allowed_packet bytes 查了一下&#xff0c;原来是MySQL默认读取执行的SQL文件最大为16M&#xff0c;我这个SQL文件260M&#xff0c;所以执行不过去 解决方法&#xff…

沙箱模式以及其使用到的IIFE

//沙箱//与外界隔绝的一个环境&#xff0c;外界无法修改该环境内任何信息&#xff0c;沙箱内的东西单独属于一个世界//360沙箱模式//将软件和操作系统进行隔离&#xff0c;以达到安全的目的//苹果手的app使用的就是沙箱模式去运行//隔离app的空间&#xff0c;每个app独立运行//…

C++从0到1的入门级教学(十)——类和对象

文章目录10 类和对象10.1 封装10.1.1 封装的意义10.1.2 struct和class的区别10.1.3 成员属性设置为私有10.2 对象的初始化和清理10.2.1 构造函数和析构函数10.2.2 构造函数的分类及调用10.2.3 关于拷贝构造函数调用时机10.2.4 构造函数调用规则10.2.5 深拷贝和浅拷贝10.2.6 初始…

js二级导航

js写二级导航要点 1.ul li 2.js获取元素 3.setInterval(function(),time); 代码如下 1 <style type"text/css">2 ul,li,body{margin:0;padding: 0;}3 #nav{width: 500px;margin: 10px auto;}4 ul li{list-style: none;}5 .clear{clear: both;}6 #n…

关于STM32的两个小问题的总结

一、最近做了一个关于自动转速测试仪的项目&#xff0c;其中用到了STM32的RTC时钟的功能&#xff0c;然后开始写代码&#xff0c;并且成功的跑了起来&#xff0c;于是将自己的板子放到桌面上让它跑了一个晚上看下误差&#xff0c;结果发现经过一晚上&#xff0c;误差并不是很大…

深度学习修炼(六)——神经网络分类问题

文章目录6 分类任务6.1 前置知识6.1.1 分类6.1.2 分类的网络6.2 动手6.2.1 读取数据6.2.2 functional模块6.2.3 继续搭建分类神经网络6.2.4 继续简化6.2.5 训练模型6.3 暂退法6.3.1 重新看待过拟合问题6.3.2 在稳健性中加入扰动6.3.3 暂退法实际的实现6.4 后话6 分类任务 在这…

修改NavigationBar的分根线颜色

[self.navigationController.navigationBar setShadowImage:[Static ColorToImage:[Static colorWithHexString:[UIColor red]]]]; Static 里的几个静态方法 (UIImage *)ColorToImage:(UIColor *)color{CGRect rectCGRectMake(0.0f, 0.0f, 1.0f, 1.0f);UIGraphicsBeginImageCo…

Java IO 之 InputStream源码(2)

Writer&#xff1a;李强强 一、InputStream InputStream是一个抽象类&#xff0c;即表示所有字节输入流实现类的基类。它的作用就是抽象地表示所有从不同数据源产生输入的类&#xff0c;例如常见的FileInputStream、FilterInputStream等。那些数据源呢&#xff1f;比如&#xf…

【CTSC2017】【BZOJ4903】吉夫特 卢卡斯定理 DP

题目描述 给你一个长度为\(n\)的数列\(a\)&#xff0c;求有多少个长度\(\geq 2\)的不上升子序列\(a_{b_1},a_{b_2},\ldots,a_{b_k}\)满足\[ \prod_{i2}^k\binom{a_{b_{i-1}}}{a_{b_i}}\mod 2>0 \]   答案对\({10}^97\)取模。 \(n\leq211985,a_i\leq 233333\) \(\forall i\…

深度学习修炼(七)——卷积神经网络

文章目录7 卷积神经网络7.1 卷积网络和传统网络的区别7.2 卷积7.2.1 卷积过程画大饼7.2.2 图像的不变性7.2.3 互相关运算*(补充)7.2.4 图像颜色通道*(补充)7.2.5 步幅7.2.6 多次卷积7.2.7 边缘填充7.2.8 特征图的大小7.2.9 卷积参数共享7.3 池化7.4 整体网络架构7.5 后话7 卷积…

Java并发编程:ThreadLocal

Java并发编程&#xff1a;深入剖析ThreadLocal ThreadLocal ThreadLocal之我见 Struts2中的设计模式----ThreadLocal模式 ThreadLocal ThreadLocal原理及其实际应用 ThreadLocal 转载于:https://www.cnblogs.com/a198720/articles/4229366.html

用递归形成树结构数据

定义一个树形实体 public class orgTrees{public orgTrees(){this.Children new List<orgTrees>();}public int Id { get; set; }public int FatherId { get; set; }public string Name { get; set; }public int Lever { get; set; }public bool HasChildren { get; se…

网络爬虫(一)——爬虫及其实现

文章目录1.1 爬虫概述1.1.3 网络爬虫和浏览器的区别1.1.2 网络爬虫的定义1.2 requests请求库1.2.1 requests基本概念1.2.2 疫情数据爬取1.2.3 get请求1.2.4 headers请求头1.2.5 Cookies验证1.3 Beautiful Soup解析库1.3.1 安装1.3.2 对象的创建1.3.3 find方法1.3.4 后话1.4 正则…

C# winform 窗体怎么隐藏标题栏,不显示标题栏

//没有标题 this.FormBorderStyle FormBorderStyle.None; //任务栏不显示 this.ShowInTaskbar false;转载于:https://www.cnblogs.com/qq260250932/p/4230472.html

sqL编程篇(三) 游标与存储过程

sql编程2 游标与存储过程 sql编程中的游标的使用&#xff1a;提供的一种对查询的结果集进行逐行处理的一种方式不用游标的处理解决方式&#xff1a;逐行修改工资update salar set 工资‘新工资’ where 雇员号0101 //通过查出雇员号而修改工资过程&#xff1a;1.定义一个游标&a…

python爬虫从入门到精通

第一讲 什么是爬虫 网络蜘蛛&#xff08;Web spider&#xff09;也叫网络爬虫&#xff08;Web crawler&#xff09;&#xff0c;蚂蚁&#xff08;ant&#xff09;&#xff0c;自动检索工具&#xff08;automatic indexer&#xff09;&#xff0c;或者&#xff08;在FOAF软件概念…

Windows五种IO模型性能分析和Linux五种IO模型性能分析

Windows五种IO模型性能分析和Linux五种IO模型性能分析 http://blog.csdn.net/jay900323/article/details/18141217 http://blog.csdn.net/jay900323/article/details/18140847 重叠I/O模型的另外几个优点在于&#xff0c;微软针对重叠I/O模型提供了一些特有的扩展函数。当使用重…

C++从0到1的入门级教学(十一)——友元

文章目录11 友元11.1 全局函数做友元11.2 友元类11.3 成员函数做友元11 友元 让我们引入一个例子来讲述友元是什么。 生活中你的家有客厅&#xff0c;有卧室&#xff0c;客厅所有来的客人都可以进去&#xff0c;但是你的卧室是私有的。对于认识的人来说你可以允许它进去&…

KeyMob:为国内应用开发者管理的广告聚合平台

为什么80%的码农都做不了架构师&#xff1f;>>> 应用开发者在应用中嵌入广告SDK的来源主要包括两种&#xff1a;使用移动广告平台与移动广告聚合平台。国内有多少家提供移动广告管理的平台&#xff1f;据统计&#xff0c;这两个版本&#xff0c;已经有四五十家。虽…