登录  | 加入社区

黑狼游客您好!登录后享受更多精彩

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

查看: 794|回复: 0

事件的ACID属性我总是傻傻分不清

[复制链接]

201

主题

201

帖子

0

现金

黑狼菜鸟

Rank: 1

积分
0
发表于 2019-3-13 06:44:07 | 显示全部楼层 |阅读模式 来自 江苏徐州
BKNn9e9C3cCv90Vv.jpg
事件的劈头

对于大部门步伐员来说,他们的使命就是把实际天下的业务场景映射到数据库天下。好比银举动了存储人们的账户信息会创建一个account表:







CREATE TABLE IF NOT EXISTS account (    id INT NOT NULL AUTO_INCREMENT COMMENT '自增id',    name VARCHAR(100) COMMENT '客户名称',    balance INT COMMENT '余额',    PRIMARY KEY (id)) Engine=InnoDB CHARSET=utf8;狗哥和猫爷是一对好基友,他们都到银行开一个账户,他们在实际天下中拥有的资产就会表现在数据库天下的account表中。好比如今狗哥有11元,猫爷只有2元,那么实际中的这个环境映射到数据库的account表就是如许:







+----+--------+---------+| id | name   | balance |+----+--------+---------+|  1 | 狗哥   |      11 ||  2 | 猫爷   |       2 |+----+--------+---------+在某个特定的时候,狗哥猫爷这些家伙在银行所拥有的资产是一个特定的值,这些特定的值也可以被形貌为账户在这个特定的时候实际天下的一个状态。随着时间的流逝,狗哥和猫爷大概连续举行向账户中存钱、取钱大概向别人转账等操纵,如许他们账户中的余额就大概发生变更,每一个操纵都相称于实际天下中账户的一次状态转换。数据库天下作为实际天下的一个映射,天然也要举行相应的变更。稳定不知道,一变吓一跳,实际天下中一些看似很简朴的状态转换,映射到数据库天下却不是那么轻易的。比方说有一次猫爷在赌场赌博输了钱,急遽打电话给狗哥要借 10 块钱,否则那些看场子的就会把本身剁了。实际天下中的狗哥走向了 ATM 机,输入了猫爷的账号以及 10 元的转账金额,然后按下确认,狗哥就拔卡走人了。对于数据库天下来说,相称于实行了下边这两条语句:



UPDATE account SET balance = balance - 10 WHERE id = 1;UPDATE account SET balance = balance + 10 WHERE id = 2;但是这里头有个题目,上述两条语句只实行了一条时突然服务器断电了咋办?把狗哥的钱扣了,但是没给猫爷转已往,那猫爷照旧逃走不了被砍死的噩运~ 纵然对于单独的一条语句,我们前边絮聒Buffer Pool时也说过,在对某个页面举行读写访问时,都会先把这个页面加载到Buffer Pool中,之后假如修改了某个页面,也不会立刻把修改同步到磁盘,而只是把这个修改了的页面加到Buffer Pool的flush链表中,在之后的某个时间点才会革新到磁盘。假如在将修改过的页革新到磁盘之前体系瓦解了那岂不是猫爷照旧要被砍死?大概在革新磁盘的过程中(只革新部门数据到磁盘上)体系奔溃了猫爷也会被砍死?
怎么才气包管让可怜的猫爷不被砍死呢?实在再细致想想,我们只是想让某些数据库操纵符合实际天下中状态转换的规则而已,计划数据库的大叔们细致盘算了盘算,实际天下中状态转换的规则有好几条,待我们逐步道来。
原子性(Atomicity)

实际天下中转账操纵是一个不可分割的操纵,也就是说要么压根儿就没转,要么转账乐成,不能存在中心的状态,也就是转了一半的这种环境。计划数据库的大叔们把这种要么全做,要么全不做的规则称之为原子性。但是在实际天下中的一个不可分割的操纵却大概对应着数据库天下多少条差别的操纵,数据库中的一条操纵也大概被分解成多少个步调(好比先修改缓存页,之后再革新到磁盘等),最要命的是在任何一个大概的时间都大概发买卖想不到的错误(大概是数据库自己的错误,大概是操纵体系错误,乃至是直接断电之类的)而使操纵实行不下去,以是猫爷大概会被砍死。为了包管在数据库天下中某些操纵的原子性,计划数据库的大叔必要费一些心机来包管假如在实行操纵的过程中发生了错误,把已经做了的操纵规复成没实行之前的样子,这也是我们后边章节要细致絮聒的内容。
隔离性(Isolation)

实际天下中的两次状态转换应该是互不影响的,好比说狗哥向猫爷同时举行的两次金额为5元的转账(假设可以在两个ATM机上同时操纵)。那么末了狗哥的账户里肯定会少10元,猫爷的账户里肯定多了10元。但是到对应的数据库天下中,事变又变的复杂了一些。为了简化题目,我们大略的假设狗哥向猫爷转账5元的过程是由下边几个步调构成的:

  • 步调一:读取狗哥账户的余额到变量 A 中,这一步调简写为read(A)。
  • 步调二:将狗哥账户的余额减去转账金额,这一步调简写为A = A - 5。
  • 步调三:将狗哥账户修改过的余额写到磁盘里,这一步调简写为write(A)。
  • 步调四:读取猫爷账户的余额到变量 B,这一步调简写为read(B)。
  • 步调五:将猫爷账户的余额加上转账金额,这一步调简写为B = B + 5。
  • 步调六:将猫爷账户修改过的余额写到磁盘里,这一步调简写为write(B)。
我们将狗哥向猫爷同时举行的两次转账操纵分别称为T1和T2,在实际天下中T1和T2是应该没有关系的,可以先实行完T1,再实行T2,大概先实行完T2,再实行T1,对应的数据库操纵就像如许:
hdMBAG91Wm9J1y9f.jpg 但是很不幸,真实的数据库中T1T2的操纵大概瓜代实行,好比如许:
D1sZsQWZsL626j92.jpg 假如按照上图中的实行次序来举行两次转账的话,终极狗哥的账户里还剩6元钱,相称于只扣了 5元钱,但是猫爷的账户里却成了12元钱,相称于多了10元钱,这银行岂不是要亏死了?

以是对于实际天下中状态转换对应的某些数据库操纵来说,不但要包管这些操纵以原子性的方式实行完成,而且要包管别的的状态转换不会影响到本次状态转换,这个规则被称之为隔离性。这时计划数据库的大叔们就必要接纳一些步伐来让访问雷同数据(上例中的A账户和B账户)的差别状态转换(上例中的T1和T2)对应的数据库操纵的实行次序有肯定规律,这也是我们后边章节要细致絮聒的内容。
同等性(Consistency)

我们生存的这个天下存在着形形色色的束缚,好比身份证号不能重复,性别只能是男大概女,高考的分数只能在 0~75 0之间,人民币面值最大只能是 100(如今是 2019 年),红绿灯只有 3 种颜色,房价不能为负的,门生要听老师话,吧啦吧啦有点儿扯远了~ 只有符合这些束缚的数据才是有用的,好比有个小孩儿跟你说他高考考了 1000 分,你一听就知道他胡扯呢。数据库天下只是实际天下的一个映射,实际天下中存在的束缚固然也要在数据库天下中有所表现。假如数据库中的数据全部符合实际天下中的束缚(all defined rules),我们说这些数据就是同等的,大概说符合同等性的。
怎样包管数据库中数据的同等性(就是符合全部实际天下的束缚)呢?这实在靠两方面的积极:

  • 数据库自己能为我们包管一部门同等性需求(就是数据库自身可以包管一部门实际天下的束缚永久有用)。
    我们知道MySQL数据库可以为表创建主键、唯一索引、外键、声明某个列为NOT NULL来拒绝NULL值的插入。好比说当我们对某个列创建唯一索引时,假如插入某条记载时该列的值重复了,那么MySQL就会报错而且拒绝插入。除了这些我们已经非常认识的包管同等性的功能,MySQL还支持CHECK语法来自界说束缚,好比如许:









CREATE TABLE IF NOT EXISTS account (    id INT NOT NULL AUTO_INCREMENT COMMENT '自增id',    name VARCHAR(100) COMMENT '客户名称',    balance INT COMMENT '余额',    PRIMARY KEY (id),    CHECK (balance >= 0) );上述例子中的CHECK语句本意是想规定balance列不能存储小于0的数字,对应的实际天下的意思就是银行账户余额不能小于0。但是很遗憾,MySQL仅仅支持CHECK语法,但现实上并没有一点卵用,也就是说纵然我们利用上述带有CHECK子句的建表语句来创建account表,那么在后续插入或更新记载时,MySQL并不会去查抄CHECK子句中的束缚是否建立。
小贴士: 别的的一些数据库,好比 SQL Server 大概 Oracle 支持的 CHECK 语法是有实着实在的作用的,每次举行插入或更新记载之前都会查抄一下数据是否符合 CHECK 子句中指定的束缚条件是否建立,假如不建立的话就会拒绝插入或更新。
固然CHECK子句对同等性查抄没什么卵用,但是我们照旧可以通过界说触发器的方式来自界说一些束缚条件以包管数据库中数据的同等性。

  • 更多的同等性需求必要靠写业务代码的步伐员本身包管。
    为创建实际天下和数据库天下的对应关系,理论上应该把实际天下中的全部束缚都反应到数据库天下中,但是很不幸,在更改数据库数据时举行同等性查抄是一个泯灭性能的工作,比方说我们为account表创建了一个触发器,每当插入大概更新记载时都会校验一下balance列的值是不是大于 0,这就会影响到插入或更新的速率。仅仅是校验一行记载符不符合同等性需求倒也不是什么大题目,有的同等性需求简直失常,比方说银行会创建一张代表账单的表,里边儿记载了每个账户的每笔生意业务,每一笔生意业务完成后,都必要包管整个体系的余额即是全部账户的收入减去全部账户的付出。假如在数据库层面实现这个同等性需求的话,每次发生生意业务时,都必要将全部的收入加起来减去全部的付出,再将全部的账户余额加起来,看看两个值相不相称。这不是搞笑呢么,假如账单表里有几亿条记载,光是这个校验的过程大概就要跑好几个小时,也就是说你在煎饼摊买个煎饼,利用银行卡付款之后要等好几个小时才气提示付款乐成,如许的性能代价是完全蒙受不起的。
    实际生存中复杂的同等性需求触目皆是,而由于性能题目把同等性需求交给数据库去办理这是不实际的,以是这个锅就甩给了业务端步伐员。比方说我们的account表,我们也可以不创建触发器,只要编写业务的步伐员在本身的业务代码里判定一下,当某个操纵会将balance列的值更新为小于 0 的值时,就不实行该操纵就好了嘛!
我们前边絮聒的原子性和隔离性都会对同等性产生影响,好比我们实际天下中转账操纵完成后,有一个同等性需求就是到场转账的账户的总的余额是稳定的。假如数据库不遵照原子性要求,也就是转了一半就不转了,也就是说给狗哥扣了钱而没给猫爷转已往,那末了就是不符合同等性需求的;雷同的,假如数据库不遵照隔离性要求,就像我们前边絮聒隔离性时举的例子中所说的,终极狗哥账户中扣的钱和猫爷账户中涨的钱大概就不一样了,也就是说不符合同等性需求了。以是说,数据库某些操纵的原子性和隔离性都是包管同等性的一种本领,在操纵实行完成后包管符合全部既定的束缚则是一种效果。那满意原子性和隔离性的操纵肯定就满意同等性么?那倒也不肯定,好比说狗哥要转账20元给猫爷,固然在满意原子性和隔离性,但转账完成了之后狗哥的账户的余额就成负的了,这显然是不满意同等性的。那不满意原子性和隔离性的操纵就肯定不满意同等性么?这也不肯定,只要末了的效果符合全部实际天下中的束缚,那么就是符合同等性的。
长期性(Durability)

当实际天下的一个状态转换完成后,这个转换的效果将永世的保存,这个规则被计划数据库的大叔们称为长期性。比方说狗哥向猫爷转账,当ATM机提示转账乐成了,就意味着这次账户的状态转换完成了,狗哥就可以拔卡走人了。假如当狗哥走掉之后,银行又把这次转账操纵给打消掉,规复到没转账之前的样子,那猫爷不就惨了,又得被砍死了,以是这个长期性黑白常紧张的。
当把实际天下的状态转换映射到数据库天下时,长期性意味着该转换对应的数据库操纵所修改的数据都应该在磁盘上保存下来,岂论之后发生了什么变乱,本次转换造成的影响都不应该被丢失掉(要否则猫爷照旧会被砍死)。
事件的概念

为了方便各人记着我们上边絮聒的实际天下状态转换过程中必要服从的4个特性,我们把原子性(Atomicity)、隔离性(Isolation)、同等性(Consistency)和长期性(Durability)这四个词对应的英文单词首字母提取出来就是A、I、C、D,轻微变更一下次序可以构成一个完备的英文单词:ACID。想必各人都是学过初高中英语的,ACID是英文酸的意思,以后我们提到ACID这个词儿,各人就应该想到原子性、同等性、隔离性、长期性这几个规则。别的,计划数据库的大叔为了方便起见,把必要包管原子性、隔离性、同等性和长期性的一个或多个数据库操纵称之为一个事件(英文名是:transaction)。
我们如今知道事件是一个抽象的概念,它实在对应着一个或多个数据库操纵,计划数据库的大叔根据这些操纵所实行的差别阶段把事件大抵上分别成了这么几个状态:

  • 运动的(active)
    事件对应的数据库操纵正在实行过程中时,我们就说该事件处在运动的状态。
  • 部门提交的(partially committed)
    当事件中的末了一个操纵实行完成,但由于操纵都在内存中实行,所造成的影响并没有革新到磁盘时,我们就说该事件处在部门提交的状态。
  • 失败的(failed)
    当事件处在运动的大概部门提交的状态时,大概碰到了某些错误(数据库自身的错误、操纵体系错误大概直接断电等)而无法继承实行,大概人为的制止当前事件的实行,我们就说该事件处在失败的状态。
  • 中断的(aborted)
    假如事件实行了半截而变为失败的状态,好比我们前边絮聒的狗哥向猫爷转账的事件,当狗哥账户的钱被扣除,但是猫爷账户的钱没有增长时碰到了错误,从而当前事件处在了失败的状态,那么就必要把已经修改的狗哥账户余额调解为未转账之前的金额,换句话说,就是要打消失败事件对当前数据库造成的影响。书面一点的话,我们把这个打消的过程称之为回滚。当回滚操纵实行完毕时,也就是数据库规复到了实行事件之前的状态,我们就说该事件处在了中断的状态。
  • 提交的(committed)
    当一个处在部门提交的状态的事件将修改过的数据都同步到磁盘上之后,我们就可以说该事件处在了提交的状态。
随着事件对应的数据库操纵实行到差别阶段,事件的状态也在不停变革,一个根本的状态转换图如下所示:
WW4zpY4i9liWHQ9U.jpg 从图中各人也可以看出了,只有当事件处于提交的大概中断的状态时,一个事件的生命周期才算是竣事了。对于已经提交的事件来说,该事件对数据库所做的修改将永世见效,对于处于中断状态的事件,该事件对数据库所做的全部修改都会被回滚到没实行该事件之前的状态。

小贴士: 此贴士处纯属扯犊子,与正文没啥关系,纯属吐槽。各人知道我们的盘算机术语根本上满是从英文翻译成中文的,事件的英文是transaction,英文直译就是生意业务,交易的意思,生意业务就是买的人付钱,卖的人交货,不能付了钱不交货,交了货不付钱把,以是生意业务自己就是一种不可分割的操纵。不知道是哪位大神把transaction翻译成了事件(我想估计是他们也想不出什么更好的词儿,只能任意找一个了),事件这个词儿完全没有生意业务、交易的意思,以是各人明白起来也会比力困难,外国人明白transaction大概更好明白一点吧~
本文节选自《MySQL是怎么运行的:从根儿上明白MySQL》,老钱和《MySQL运维内参》周总都尽力保举的小册子,我也感到作者气概气派惊人,能辞职写这么一本小册子,着实是敬佩,出于这种气概气派,我硬着头皮保举一下。


保举语:偶尔熟悉的一位朋侪,近来写了一本关于 MySQL 非常不错的小册。固然叫小册,内容非常翔实。值得分享给各人,从小白的角度出发,用比力普通的语言解说关于MySQL内核的一些焦点概念,好比记载、索引、页面、表空间、查询优化、事件和锁等内容,统共的字数约莫是三四十万字,配有上百幅原创插图,完满是册本质量尺度,非常专心,很得当对数据库明白还不敷深的同砚(好比我这个菜鸟)此中另有特么插入了一些段子~~~我也是很敬佩~~感爱好的可扫描下方二维码购买。


vGdqim16nZlqOtDg.jpg



保举阅读:

模仿真实情况下超简朴超具体的 MySQL 5.7 安装

关系型数据库 MySQL 之 InnoDB 体系布局

关系型数据库 MySQL 表索引和视图详解

关系型数据库 MySQL 体系布局详解

关系型数据库 MySQL 表相干操纵

Linux 下 CentOS 7 安装教程

MySQL 底子知识学习

十大资源分享篇一



资源分享:



5T 技能资源大放送!包罗但不限于:Linux、Python、Oracle、MySQL、Java、前端、大数据、人工智能等,详细获取方式可关注本公众号大概添加我微信获取~~



BCuuISSclbNQ22jI.jpg mp43P4K3P4B03sFc.jpg


添加微信,可参加资源技能交换群


SiG9dG08bZ8NgINo.jpg
长按 辨认二维码 即可关注!
写作不易,不要错过这个悦目哦!

C1JZJs77cQwjs5Z5.jpg




上一篇:在CentOS7.4下OpenSSH升级到7.9p1
下一篇:2019微生物组—宏基因组分析专题培训第三期
您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

 

QQ|申请友链|小黑屋|手机版|Hlshell Inc. ( 豫ICP备16002110号-5 )

GMT+8, 2024-5-1 14:44 , Processed in 0.105812 second(s), 47 queries .

HLShell有权修改版权声明内容,如有任何爭議,HLShell將保留最終決定權!

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表