数据库事务基础

一、为什么需要事务?

举个例子:
A 和 B 账户各有 50 元余额,现在 A 要给 B 转账 10 元,刨除掉具体的业务逻辑和工作流程,仅考虑数据库层面的操作:A 账户-10,B 账户+10 。
如果没有事务,就只能让两个 update 操作串行执行:

// 代码片段1
run("update account set balance=balance-10 where account_id=A");
run("update account set balance=balance+10 where account_id=B");
图1

如图1,对于这个转账操作,我们的期望是:

  • 代码片段1执行前,数据库数据:A 余额 50,B 余额 50。
  • 代码片段1执行后,数据库数据:A 余额 40,B 余额 60。

但是,如果执行完 A-10 后,系统崩溃了,B+10 没能得到执行。则:

  • 代码片段1执行前,数据库数据:A 余额 50,B 余额50。
  • 代码片段1执行后,数据库数据:A 余额 40,B 余额50。
  • 在此场景下,对 A 来说,这个转账操作是成功了的,毕竟钱都扣掉了,但 B 却没有收到对应的款项,也就是说从 A 账户扣掉的 10 块钱凭空消失了。这在实际业务中是不可接受的。

要解决这个问题,就必须有一套机制,来保证 A-10 和 B+10 这两个操作同时成功,或同时失败,以确保两个 update 操作执行前后的数据的一致性、正确性和完整性。

这套机制,就是“事务”。

二、事务定义

数据库事务 是可以作为一个完整的逻辑工作单元来执行的不可分割的一组操作,这些操作要么全部执行,要么全部不执行。

  • 在关系型数据库中,事务可以是一条sql语句,也可以是多条sql语句。
  • 在此基础之上,为了保证这一组操作执行结果的正确性和有效性,事务又附加了一些条件,就是ACID了。

ACID 的关注点和对事务的要求如下:


ACID

一致状态,是指数据处于一种语义上的有意义且正确的状态。
隔离性还有其他的称呼,如:并发控制、可串行化、锁等。

三、事务并发问题和隔离模式

并发访问场景下,若没有采取必要的隔离措施,会存在一些读写问题,包括:

  • 3 类数据读问题:脏读、不可重复读和幻读。
  • 2 类数据更新问题:第一类丢失更新、第二类丢失更新。
并发读写问题

数据库提供不同级别的事务隔离模式,解决部分或全部上述的读写问题,SQL 规范定义了四种级别的隔离模式(级别由低到高):

  1. Read Uncommitted(读未提交):最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
  2. Read Committed(读已提交):只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。
  3. Repeated Read(可重复读):在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。
  4. Serialization(串行化):事务串行化执行,最高隔离级别,牺牲系统的并发性,将所有事务串行执行。可以解决并发事务的所有问题。

事务的隔离级别和数据库并发性是成反比的,隔离级别越高,并发性越低。

四、ACID的实现技术

ACID 的实现技术包括:并发控制、日志管理、备份恢复、锁管理、MVCC等内容。
其中,并发控制和日志技术是核心。

4.1 并发控制技术

并发控制技术是实现原子性、一致性和隔离性的重要技术之一。并发控制的本质就是要对并发的事务实现正确又高效的调度。

从实现思想的角度看,并发控制技术分两类:

  • 乐观并发控制,Optimistic Concurrency Control,OOC,事后检查。
  • 悲观并发控制,Pessimistic Concurrency Control,PCC,提前预防。

从实现技术角度,并发控制机制有如下几类:

  1. 基于锁的并发控制机制

基于锁的并发控制机制是最常见的一种并发控制机制,事务中可能涉及到的一些锁的概念如下图:


  1. 基于时间戳/数据版本的并发控制

基于数据版本的并发访问控制,是通过给数据表加一个版本号或时间戳字段实现。

  • 当读取数据时,将 version字段的值一同读出,数据每更新一次,对此 version 值加一。
  • 当提交更新的时候,判断当前版本信息与第一次取出来的版本值大小,如果数据库表当前版本号与第一次取出来的 version 值相等,则予以更新,否则认为是过期数据,拒绝更新。

基于时间戳的并发控制类似,把版本号换成时间戳就行了。

  1. 基于MVCC的并发控制

MVCC(Multi-Version Concurrent Control),即多版本并发控制协议,是个行级锁的变种,它在普通读情况下避免了加锁操作,因此开销更低,同时在保证数据一致性的前提下,提供一种高并发的访问性能。

虽然不同数据库或数据库引擎对 MVCC 的实现不同,但通常都是实现非阻塞读,对于写操作只锁定必要的行:

  • 第一种实现方式:将数据记录的多个版本保存在数据库中,当这些不同版本数据不再需要时,垃圾回收器回收这些记录。——PostgreSQL 和 Firebird/Interbase 采用。
  • 第二种实现方式:只在数据库保存最新版本的数据,但是会在使用undo时动态重构旧版本数据。——Oracle 和 MySQL/InnoDB 采用。

4.2 日志技术

数据库的日志可以大体分为3类:binlog、redo log、undo log。

其中,binlog是Server层记录的日志, redo log 和 undo log 是数据库存储引擎层的日志。

大部分关系型数据库系统是通过 redo log 和 undo log 来实现事务的原子性、一致性和持久性,同时也用于支持数据备份和恢复:

  • redo log,记录数据被修改后的值,可以用来恢复未写入 data file 的已成功事务更新的数据。redo log 又包括:redo log buffer 和 redo log file,一个写内存,一个写硬盘。
  • undo log,记录数据被修改前的值,可以用来在事务失败时进行 rollback。

举个例子,假设 A=1且 B=2,某事务 T 要做 A=3 和 B=4,则

  1. 事务简化过程:
1.start
2.A=1——>undo log
3.set A=3
4.A=3——>redo log buffer
5.B=2——>undo log
6.set B=4
7.B=4——>redo log buffer
8.redo log buffer——>redo log file
9.commit
  1. undo 和 redo 日志:
// undo日志:
<T,A,1>
<T,B,2>
// redo日志:
<T,A,3>
<T,B,4>
  1. 数据恢复(重做、撤销)
    若执行 9 时出现系统异常,则下次启动时可以通过 redo log 重做该事务。
    若执行 6 时出现异常,则可以通过 undo log 撤销已经做过的修改。
  2. undo/redo日志
    也有把 undo 和 redo 结合起来的做法,叫做 Undo/Redo 日志,在前面中的例子
    Undo/Redo 日志为:
<T, A, 1, 3>
<T, B, 2, 4>

五、参考文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容

  • 导语:计算机硬件在飞速发展,数据规模在急速膨胀,但是数据库仍然使用是十年以前的架构体系,WiredTiger 尝试...
    isgiker阅读 3,387评论 0 7
  • 很多人喜欢这篇文章,特此同步过来 由浅入深谈论spring事务 前言 这篇其实也要归纳到《常识》系列中,但这重点又...
    码农戏码阅读 4,687评论 2 59
  • 数据库范式 https://www.zhihu.com/question/24696366 索引 索引可以加快数据...
    EakonZhao阅读 3,169评论 3 23
  • 引言 事务,体现的是部分与整体的思想,多个部分组成一个整体,要么全部生效,要么全部失效。事务就是实现这种效果的一个...
    程序猿胖子阅读 435评论 0 2
  • 人到中年万事休,每天虚度光阴收。远山金矿力不从,近水楼台看月变。一天一天方步行,一杯一怀早茶饮。日出东方西山落,也...
    甘朝武阅读 127评论 0 0