小白和小菜都能看懂的MySQL事务机制

感谢你的三连,关注不迷路,我是Bill,一个5年京漂,有问题可以私信我,我会尽力帮助解决你的问题。

什么是事务?

数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由开始和结束之间执行的全部数据库操作组成。

这是百科的定义,也是我们在面试的时候最常回答的关键字。

可以这么说:事务是数据库执行过程的一个逻辑单位,由一个有限的数据库操作序列组成

举例来说,当我们购物下订单时,有这么两个操作(当然不止这俩):付款,减库存。这两个操作序列就是一个事务,他不能拆分执行,必须同时成功和失败。

当我们面试时最常遇到的问题是什么

或者不那么世俗的说——毕竟我们学习并不全是为了面试嘛,啊呸!不面试谁看那么多,脑子内存本来就不大。

image

编辑搜图

请点击输入图片描述

事务的4大特性

  1. A (Atomicity) 原子性:事务的操作序列不可再拆分:这也是都成功都失败的意思。

  2. C (Consistent) 一致性:事务的执行使数据从一个状态转换为另一个状态,但是对于整个数据的完整性保持稳定。

  3. I(Isolation)隔离性:隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

  4. D(Durable)持久性:久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

关于ACID抢眼回答:

数据库的每一个操作其实是一条日志。

原子性,在 InnoDB 里面是通过 undo log 来实现的,它记录了数据修改之前的值(逻辑日志),一旦发生异常,就可以用 undo log 来实现回滚操作。

持久性怎么实现呢?数据库崩溃恢复(crash-safe)是通过什么实现的?

是通过 redo log 和 double write 双写缓冲来实现的,我们操作数据的时候,会先写到内存的buffer-pool中,同时记录 redo log,如果在刷盘之前出现异常,在重启后就可以读取 redo log 的内容,写入到磁盘,保证数据的持久性。

当然,恢复成功的前提是数据页本身没有被破坏,是完整的,如果数据页本身损坏了,这个可以通过双写缓冲 (double write)保证。

说了这么多事务,你甚至可能在实际编程中并没有手动操作过事务,那么如何手动开启和关闭事务呢?

image

编辑搜图

请点击输入图片描述

Mysql数据库默认是开启自动提交事务的,也就是说当你执行update/delete/insert操作时数据库引擎会自动开启一个事务,并且在操作完成后自动提交事务。

事务并发产生的问题

  • 脏读,读到了其他事务还没提交的数据

  • 不可重复读,读到了其他事务提交之后的数据,数据变化了(update/delete)

  • 幻读,读到了其他事务提交之后的数据,只有数据增加了行才叫幻读(insert)

你可能会说,事务不是有隔离性吗,为什么还有这么多问题?好了继续往下看

事务隔离级别

  • Read Uncommited 未提交读,顾名思义,可以读到其他事务没有提交的数据,会产生脏读

事务操作时并不隔离其他的事务,比如以下操作:

image

编辑搜图

请点击输入图片描述

而如果此时事务1 回滚了事务,事务2就读到了脏数据;

这种隔离机制在数据库实际使用中,显然不合适,但有助于理解其他事务。

  • Read Commited 已提交读,只能读取其他事务已经提交的数据,不能读取到其他事务未提交的数据,它解决了脏读的问题, 但是会出现不可重复读的问题。

事务只能读取其他事务提交之后的数据,我们来模拟以下这个过程会出现的问题:

image

编辑搜图

请点击输入图片描述

可以看到,这种隔离级别会导致数据在一个事务两次读取的数据不一致,也就是不可重复读;

  • Repeatable Read 可重复读,它解决了不可重复读的问题, 也就是在同一个事务里面多次读取同样的数据结果是一样的,但是在这个级别下,没有解决幻读的问题。

这也是最常用的事务隔离机制,他可以保证在一个事务里读取的数据是一样的,也就是数据的可重复读。你可能会问,数据库是如何实现可重复读的?这个问题会在之后解答,先来看看什么是幻读。

一个事务前后两次读取数据数据不一致,是由于其他事务插入数据造成的,这种情况我们把它叫做幻读

比如:

image

编辑搜图

请点击输入图片描述

第二次查询我们发现多了一条数据,这就叫幻读。需要记住的是只有其他事务插入导致的数据不一致才叫幻读。

  • Serializable(串行化),最后一个是串行的隔离级别,也是最严格的隔离级别,它要求事务必须排队执行,解决了幻读。但这大大影响了效率。也比较少用。

所以你会说,既然我们比较常用的是RR(可重复读)的隔离级别会有幻读的情况,那为什么还经常使用它?其实在MySQL的InnoDB引擎使用RR的隔离级别但配合锁的机制已经避免了幻读情况。

我们先来看一下MySQL是如何实现数据的可重复的。

有两种方案。

  • LBCC (Lock Based Concurrency Control),意思是读取数据的时候锁定它,不允许其他事务操作,数据自然也不会变化。这种方案我们叫做基于锁的并发控制简称LBCC。一个事务读取的时候不允许其他时候修改,那就意味着不支持并发的读写操作,而我们的大多数应用都是读多写少的,这样会极大地影响操作数据的效率。

  • MVCC (Multi Version Concurrency Control), 意思是多版本并发控制,另一种解决方案是如果要让一个事务前后两次读取的数据保持一致, 那么我们可以在修改数据的时候给它建立一个备份或者叫快照,后面再来的事务读取这个快照就行了。

MVCC的核心思想是:可以查到在当前事务开始之前已经存在的数据,即使它在后面被其他事务修改或者删除了。而当前事务之后新增的数据,当前事务是查不到的。

那么问题来了,如何保证当前事务数据的一致性呢?也就是说怎么保证数据被其他事务修改和删除或者新增了数据,而当前事务并不受影响呢?

读取数据事务开始的时候,MySQL为事务创建了快照,也就是在事务内查询的数据都是快照版本,这样就可以保证数据的一致性。

那么快照又是如何实现的呢?

InnoDB 为每行记录都实现了两个隐藏字段:

  1. DB_TRX_ID,6 字节:插入或更新行的最后一个事务的事务ID,事务编号是自动递增的(我们把它理解为创建版本号,在数据新增或者修改为新数据的时候,记录当前事务ID)

  2. DB_ROLL_PTR,7 字节:回滚指针(我们把它理解为删除版本号,数据被删除或记录为旧数据的时候,记录当前事务 ID)。

我们把这两个事务ID理解为版本号。

从插入数据开始,我们来看一下MySQL如何用这两个版本号来隔离事务。

image

编辑搜图

请点击输入图片描述

此时又有一个事务进来,增加了一条数据并提交结束。

image

编辑搜图

请点击输入图片描述

MVCC 的查找规则1:只能查找创建时间小于等于当前事务 ID 的数据

image

编辑搜图

请点击输入图片描述

再次回到事务2查询

image

编辑搜图

请点击输入图片描述

MVCC 的查找规则2: 能查找删除时间大于当前事务id的数据,也就是在事务之后删除的数据在当前事务依然能查得到。

事务5,尝试修改数据

image

编辑搜图

请点击输入图片描述

此时回到事务2再次查询数据

image

编辑搜图

请点击输入图片描述

按照查找规则:只能查找创建时间小于等于当前事务 ID 的数据,和删除时间大于当前事 务 ID 的行(或未删除)。

解释:id为1的数据删除版本大于当前事务2,创建版本小于事务2,依然可以查到,

id为2的数据创建版本为1的数据,小于事务2,删除版本大于事务2,可以查到

id为3的数据创建版本为3大于事务2,查不到;

id为2的数据创建版本为5的数据,大于事务2,依然查不到;

所以,在事务2内,无论外部发生了什么翻天覆地的变化,事务2自始自终查到的都是自己的快照数据,保证了数据的一致性,一定要理解MVCC的核心思想。

之后会更新结合锁机制,InnoDB是如何在RR级别解决幻读的。

祝你好运,关注我嘛~

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

推荐阅读更多精彩内容