彻底理解数据库事务

时间:2021-03-27 04:25:37

在计算机术语中,事务(Transaction)是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit),通常就是指数据库事务

概念

一个数据库事务通常包含对数据库进行读或写的一个操作序列。它的存在有以下两个目的:

  • 为数据库操作提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法;
  • 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。

当一个事务被提交给 DBMS(数据库管理系统),则 DBMS 需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中。如果事务中有的操作没有成功完成,则事务中的所有操作都需要被回滚,回到事务执行前的状态(要么全执行,要么全都不执行);同时,该事务对数据库或者其他事务的执行无影响,所有的事务都好像在独立的运行。

但在现实情况下,操作失败的风险很高。在一个数据库事务的执行过程中,有可能会遇上事务操作失败、数据库系统或操作系统失败,甚至是存储介质失败等情况。这便需要 DBMS 对一个执行失败的事务执行恢复操作,将其数据库状态恢复到一致状态(数据的一致性得到保证的状态)。为了实现将数据库状态恢复到一致状态的功能,DBMS 通常需要维护事务日志以追踪事务中所有影响数据库数据的操作。

特性

并非任意的对数据库的操作序列都是数据库事务,事务应该具有 4 个属性,分别为:原子性、一致性、隔离性和持久性。这四个属性通常称为ACID特性。

  • 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行;
  • 一致性(Consistency):事务应确保数据库的状态从一个一致状态转为另一个一致状态,一致状态的含义是数据库中的数据应满足完整性约束;
  • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行;
  • 持久性(Durability):一个事务一旦提交,他对数据库的修改应该永久保存在数据库中。

举例

用一个常用的“A 账户向 B 账号汇钱”的例子来说明如何通过数据库事务保证数据的准确性和完整性。熟悉关系型数据库事务的都知道从帐号 A 到帐号 B 需要 6 个操作,分别为:

  1. 从 A 账号中把余额读出来(500)
  2. 对 A 账号做减法操作(500 - 100)
  3. 把结果写回 A 账号中(400)
  4. 从 B 账号中把余额读出来(500)
  5. 对 B 账号做加法操作(500 + 100)
  6. 把结果写回 B 账号中(600)

原子性:

保证 1-6 所有过程要么都执行,要么都不执行。一旦在执行某一步骤的过程中发生问题,就需要执行回滚操作。 假如执行到第 5 步的时候,B 账户突然不可用(比如被注销),那么之前的所有操作都应该回滚到执行事务之前的状态。

一致性:

在转账之前,A 和 B 的账户*有 500 + 500 = 1000 元钱。在转账之后,A 和 B 的账户中也应该共有 400 + 600 = 1000 元钱。也就是说,数据的状态在执行该事务操作之后从一个状态改变到了另外一个状态。同时一致性还能保证账户余额不会变成负数等。

隔离性:

在 A 向 B 转账的整个过程中,只要事务还没有提交(commit),查询 A 账户和 B 账户的时候,两个账户里面的钱的数量都不会有变化。如果在 A 给 B 转账的同时,有另外一个事务执行了 C 给 B 转账的操作,那么当两个事务都结束的时候,B 账户里面的钱应该是 A 转给 B 的钱加上 C 转给 B 的钱再加上自己原有的钱。

持久性:

一旦转账成功(事务提交),两个账户的里面的钱就会真的发生变化,会把数据写入数据库做持久化保存。

一致性与原子性的关系:

一致性与原子性是密切相关的,原子性的破坏可能导致数据库的不一致,数据的一致性问题并不都和原子性有关。比如上面的例子,在第 5 步的时候,对 B 账户做加法时只加了 50 元。那么,该过程可以符合原子性,但是数据的一致性就出现了问题。因此,事务的原子性与一致性缺一不可。


转载声明:本文转自「Hollis」,彻底理解数据库事务