事务简介

参考:王珊《数据库系统概论》、掘金小册《MySQL是怎样运行的》

事务的概念:AICD

==事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位。==一个程序中包含多个事务

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

1、原子性(Atomicity)、隔离性(Isolation)、一致性(Consistency)、持久性(Durability)
这四种特性称为 AICD
我们把需要保证原子性、隔离性、一致性、持久性的一个或多个数据库操作称之为一个事务

  • 原子性:事务是数据库的逻辑工作单位,事务中包含的诸多操作要么全做,要么全不做。
  • 隔离性:一个事务的执行不能被其他事务干扰。即一个事务的内部操作及使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能相互干扰。
  • 一致性:数据库中的数据全部符合现实世界中的约束
    1、数据库本身能为我们保证一部分一致性需求:比如为表建立主键、唯一索引、外键、声明某个列为NOT NULL等
    2、更多的一致性需求需要靠写业务代码的程序员自己保证
    3、数据库某些操作的原子性和隔离性都是保证一致性的手段,在操作执行完成后保证符合所有既定的约束则是一种结果
  • 持久性:当现实世界的一次状态转换完成后,这个转换结果将永久的保留,映射到数据库世界,持久性意味着该转换对应的数据库操作所修改的数据都应该在磁盘上保留下来,不论之后发生了什么事故,本次转换造成的影响都不应丢掉

2、事务的状态
事务是一个抽象的概念,对应着一个或者多个数据库操作,根据这些操作所执行的不同阶段把事务大致划分为几种状态:

  • 活动的:事务对应的数据库操作正在执行过程中
  • 部分提交的:当事务的最后一个操作执行完成,但由于操作都在内存中执行,所造成的影响并没有刷新到磁盘,称事务处于部分提交阶段
  • 失败的:当事务处于活动或部分提交状态,可能遇到了某些错误而无法继续执行、或者人为的停止当前事务的执行,我们称事务处于失败的状态
  • 中止的:如果事务执行了半截而变为失败的状态,就要撤销失败事务对当前数据库的影响,这个撤销过程称之为回滚。当回滚操作完成,也就是数据库恢复到了执行事务之前的状态,我们称事务处于中止状态
  • 提交的:当一个部分提交的状态的事务将修改过的数据都同步到磁盘上之后,我们称事务处于提交了的状态
    事务简介_第1张图片
    只有当事务处于提交的或者中止的状态时,一个事务的生命周期才算是结束了。对于已经提交的事务来说,该事务对数据库所做的修改将永久生效,对于处于中止状态的事务,该事务对数据库所做的所有修改都会被回滚到没执行该事务之前的状态。

MySQL中事务的语法

事务本质上是一系列数据库操作,只是这些操作符合ACID特性
1、开启事务

BEGIN [WORK];(WORK可有可无)
START TRANSACTION;
该语句后面可跟修饰符:
(1)READ ONLY :只读事务//属于该事务的数据库操作只能读取数据,而不能修改数据。
//其实只读事务中只是不允许修改那些其他事务也能访问到的表中的数据,
//对于临时表来说(我们使用CREATE TMEPORARY TABLE创建的表),由于它们只能在当前会话中可见,
//只读事务其实也是可以对临时表进行增、删、改操作的。
(2)READ WRITE:读写事务
//属于该事务的数据库操作既可以读取数据,也可以修改数据。
(3)WITH CONSISTENT SNAPHOT:启动一致性读
多个修饰符用逗号分开

Tips:READ ONLY和READ WRITE是用来设置所谓的事务访问模式的,就是以只读还是读写的方式来访问数据库中的数据,一个事务的访问模式不能同时既设置为只读的也设置为读写的,所以我们不能同时把READ ONLY和READ WRITE放到START TRANSACTION语句后边。另外,如果我们不显式指定事务的访问模式,那么该事务的访问模式就是读写模式。

2、提交事务:
开启事务之后就可以继续写需要放到该事务中的语句了,当最后一条语句写完了之后,我们就可以提交该事务了

COMMIT [WORK];

3、手动中止事务
如果我们写了几条语句之后发现上边的某条语句写错了,我们可以手动的使用下边这个语句来将数据库恢复到事务执行之前的样子:

ROLLBACK [WORK];
ROLLBACK语句就代表中止并回滚一个事务,后边的WORK可有可无类似的

Tips:这里需要强调一下,ROLLBACK语句是我们程序员手动的去回滚事务时才去使用的,如果事务在执行过程中遇到了某些错误而无法继续执行的话,事务自身会自动的回滚

4、支持事务的存储引擎:InnoDB和NDB存储引擎
如果某个事务中包含了修改使用不支持事务的存储引擎的表,那么对该使用不支持事务的存储引擎的表所做的修改将无法进行回滚。

5、自动提交

MySQL中有一个系统变量autocommit:

mysql> SHOW VARIABLES LIKE 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.01 sec)

可以看到它的默认值为ON,也就是说默认情况下,如果我们不显式的使用START TRANSACTION或者BEGIN语句开启一个事务,那么每一条语句都算是一个独立的事务,这种特性称之为事务的自动提交。

当然,如果我们想关闭这种自动提交的功能,可以使用下边两种方法之一:

  • 显式的的使用START TRANSACTION或者BEGIN语句开启一个事务。
    这样在本次事务提交或者回滚前会暂时关闭掉自动提交的功能。
  • 把系统变量autocommit的值设置为OFF,就像这样:
SET autocommit = OFF;

这样的话,我们写入的多条语句就算是属于同一个事务了,直到我们显式的写出COMMIT语句来把这个事务提交掉,或者显式的写出ROLLBACK语句来把这个事务回滚掉。

6、隐式提交

当我们使用START TRANSACTION或者BEGIN语句开启了一个事务,或者把系统变量autocommit的值设置为OFF时,事务就不会进行自动提交,但是如果我们输入了某些语句之后就会悄悄的提交掉,就像我们输入了COMMIT语句了一样,这种因为某些特殊的语句而导致事务提交的情况称为隐式提交:

(1)定义或修改数据库对象的数据定义语言(Data definition language,缩写为:DDL)
所谓的数据库对象,指的就是数据库、表、视图、存储过程等等这些东西。当我们使用CREATE、ALTER、DROP等语句去修改这些所谓的数据库对象时,就会隐式的提交前边语句所属于的事务,就像这样:

BEGIN;

SELECT ... # 事务中的一条语句
UPDATE ... # 事务中的一条语句
... # 事务中的其它语句

CREATE TABLE ... # 此语句会隐式的提交前边语句所属于的事务在这里插入代码片

(2)隐式使用或修改mysql数据库中的表

当我们使用ALTER USER、CREATE USER、DROP USER、GRANT、RENAME USER、REVOKE、SET PASSWORD等语句时也会隐式的提交前边语句所属于的事务。

(3)事务控制或关于锁定的语句

当我们在一个事务还没提交或者回滚时就又使用START TRANSACTION或者BEGIN语句开启了另一个事务时,会隐式的提交上一个事务,比如这样:

BEGIN;

SELECT ... # 事务中的一条语句
UPDATE ... # 事务中的一条语句
... # 事务中的其它语句

BEGIN; # 此语句会隐式的提交前边语句所属于的事务

或者当前的autocommit系统变量的值为OFF,我们手动把它调为ON时,也会隐式的提交前边语句所属的事务。

或者使用LOCK TABLES、UNLOCK TABLES等关于锁定的语句也会隐式的提交前边语句所属的事务

(4)加载数据的语句
比如我们使用LOAD DATA语句来批量往数据库中导入数据时,也会隐式的提交前边语句所属的事务。

(5)关于MySQL复制的一些语句
使用START SLAVE、STOP SLAVE、RESET SLAVE、CHANGE MASTER TO等语句时也会隐式的提交前边语句所属的事务。
其它的一些语句

(6)使用ANALYZE TABLE、CACHE INDEX、CHECK TABLE、FLUSH、 LOAD INDEX INTO CACHE、OPTIMIZE TABLE、REPAIR TABLE、RESET等语句也会隐式的提交前边语句所属的事务。

7、保存点

如果你开启了一个事务,并且已经敲了很多语句,忽然发现上一条语句有点问题,你只好使用ROLLBACK语句来让数据库状态恢复到事务执行之前的样子,然后一切从头再来,总有一种一夜回到解放前的感觉。

所以设计数据库的大叔们提出了一个保存点(英文:savepoint)的概念,就是在事务对应的数据库语句中打几个点,我们在调用ROLLBACK语句时可以指定会滚到哪个点,而不是回到最初的原点。定义保存点的语法如下:

SAVEPOINT 保存点名称;

当我们想回滚到某个保存点时,可以使用下边这个语句(下边语句中的单词WORK和SAVEPOINT是可有可无的):

ROLLBACK [WORK] TO [SAVEPOINT] 保存点名称;

不过如果ROLLBACK语句后边不跟随保存点名称的话,会直接回滚到事务执行之前的状态
如果我们想删除某个保存点,可以使用这个语句:

RELEASE SAVEPOINT 保存点名称;

数据库恢复概述

尽管数据库采取了各种各样的保护措施,来防止数据库的完整性和安全性被破坏,保证并发事务的正确执行,但是计算机系统的软硬件故障、操作员的失误以及恶意的破坏是不可避免的,这些故障轻则造成运行事务非正常中断,重则破坏数据库。

数据库管理系统必须具有把数据库从错误状态恢复到某一已知的正确状态(也称为一致状态或完整状态)的功能,这就是数据库的恢复。

恢复的原理:冗余
也就是说,数据库中任何一部分被破坏或不正确的数据可以根据存储在系统别处的冗余数据重建

故障种类

  • 1、事务内部的故障:不破坏数据库
    更多的是非预期的,不能由应用程序处理。如运算溢出、并发事务发生死锁而被选中撤销该事务、违反了某些完整性限制而被终止等。

    事务故障意味着事务没有达到预期的终点,因此,数据库可能处于不正确状态。恢复程序要在不影响其他事务运行的情况下,强行回滚该事务,即撤销事务已经做出的任何对数据库的修改,就像事务没有启动过一样。

    这类恢复操作称为 事务撤销(UNDO)

  • 2、系统故障:不破坏数据库
    系统故障是指造成系统停止运转的各种事件,使得系统要重新启动
    例如:特定类型的硬件错误(CPU故障)、操作系统故障、DBMS故障、系统断电等。这类故障影响正在运行的事务,但是不破坏数据库。此时主存内容,尤其是数据库缓冲区(在内存)的内容都将丢失,所有运行事务都非正常终止。一些尚未完成的事务的结果可能已被送入物理数据库,因此要清楚事务对数据库的所有修改

    一方面,系统重新启动时要让所有非正常终止事务的回滚,强行撤销所有未完成的的事务;

    另一方面,将已提交事务的结果重新写入数据库。

    因此,系统重新启动后,恢复子系统需要撤销所有未完成的事务外,还需要重做(REDO)所有已提交的事务,以使数据库真正恢复到一致状态。

  • 3、介质故障:破坏数据库
    系统故障称为软故障,介质故障称为硬故障,指外存故障。

  • 4、计算机病毒:人为破坏数据库

恢复的实现技术

1、如何建立冗余数据,以及如何利用这些冗余数据实现数据库恢复
2、建立冗余数据的常用技术:数据转储和登记日志文件(logging)

1、数据转储

所谓转储就是数据库管理员定期的将整个数据库复制到磁带、磁盘或其他存储介质上保存起来的过程。这些备用数据称为后备副本或后援副本。
当数据库遭到破坏可以将后备副本重新装入,但是重装后备副本只能将数据库恢复到转储时的状态,要想恢复到故障发生的状态,必须重新运行自转储以后的所有更新事务。
事务简介_第2张图片

2、登记日志文件

日志文件是用来记录事务对数据库的更新操作的文件

分为以记录为单位的日志文件和以数据块为单位的日志文件

1、以记录为单位的日志文件

  • 各个事务的开始标记
  • 各个事务的结束标记
  • 各个事务的所有更新操作
    上面三种要登记的内容均作为日志文件中的一个日志记录,每个日志记录包括的主要内容有:
  • 事务标识(表明是哪个事务)
  • 操作的类型(插入、删除、修改)
  • 操作对象(记录内部标识)
  • 更新前数据的旧值
  • 更新后数据的新值

2、对于以数据块为单位的日志文件,日志记录的内容包括事务标识和被更新的数据块

3、日志文件的作用:

  • 事务故障恢复和系统故障恢复必须用日志文件
  • 在动态转储方式中必须建立日志文件 ,后备副本和日志文件结合才能有效的恢复数据库
  • 在静态转储方式中也可以建立日志文件,当数据库毁坏后可重新装入后援副本把数据库恢复到转储结束时刻的正确状态,如何利用日志文件对已完成的事务进行重做处理,对故障发生时尚未完成的事务进行撤销处理。这样不必运行那些已完成的事务程序就可把数据库恢复到故障前某一状态

4、登记日志文件要遵循的原则:

  • 登记的次序严格按并发事务执行的时间次序
  • 必须先写日志文件,后写数据库

恢复策略

事务故障的恢复

利用日志文件撤销(UNDO)此事务对数据库的修改

系统故障的恢复

系统故障造成数据库不一致的原因:
1、未完成事务对数据库的更新可能已写入数据库
2、已提交事务对数据库的更新还留在缓冲区没有来得及写入数据库
因此恢复操作包括:
撤销故障发生时未完成的事务,重做已完成的事务

介质故障的恢复

重装数据库,然后重做已完成的事务

具有检查点的恢复技术

数据库镜像

你可能感兴趣的:(数据库)