提到MySQL的事务,我相信对MySQL有了解的同学都能聊上几句,无论是面试求职,还是日常开发,MySQL的事务都跟我们息息相关。
而事务的ACID(即原子性Atomicity、一致性Consistency、隔离性Isolation、持久性Durability)可以说涵盖了事务的全部知识点,所以,我们不仅要知道ACID是什么,还要了解ACID背后的实现,只有这样,无论在日常开发还是面试求职,都能无往而不利。
上一篇 跟面试官侃半小时MySQL事务隔离性,从基本概念深入到实现 主要围绕“隔离性”展开,从基本概念,到隔离性的实现,最后以一个实战案例进行融会贯通。本篇内容将介绍原子性、一致性、持久性相关实现,由于这部分内容可能很多人会相对陌生,因为日常业务开发可能不太会去接触和深究,但是了解完后,你对MySQL会有更深刻的认识。
1.基本概念
- 原子性。
整个事务是不可分割的最小单位,事务中任何一个语句执行失败,所有已经执行成功的语句也要回滚,整个数据库状态要恢复到执行事务前到状态。
- 一致性。
事务将数据库从一种状态转变为下一种一致的状态。在事务的前后,数据库的完整性约束没有被破坏。(事务的acid不是完全正交的,尤其是一致性,可能跟原子性、隔离性都有一定关系,后面会看到)
- 持久性。
事务一旦提交,那么就是永久性的,不会因为宕机等故障导致数据丢失(外力影响不保证,比如磁盘损害)。持久性是保证了数据库的高可靠性(High Reliability),而不是高可用性(Hign Availability)。高可用性并不能通过事务来保证。
2.持久性的实现
MySQL的innoDB存储引擎,使用Redo log保证了事务的持久性。
当事务提交时,必须先将事务的所有日志写入日志文件进行持久化,就是我们常说的WAL(write ahead log)机制(这个技术是保障持久性的关键技术,在HBase中也扮演重要角色,有兴趣的同学可以参考我之前关于HBase的文章)。这样才能保证断电或宕机等情况发生后,已提交的事务不会丢失,这个能力称为 crash-safe。
下面深入聊一聊redo log的机制,给大家更深刻的理解。
Redo log包括两部分,重做日志缓冲(redo log buffer)和重做日志文件(redo log file),前者是易失的缓存,后者是持久化的文件。
举一个事务的例子:
- 步骤1:begin;
- 步骤2:insert into t1 …r
- 步骤3:insert into t2 …
- 步骤4:commit;
这个事务的写入过程实际拆解如下:
innodb缓冲池的概念本文就不展开说明了,以后有机会可以展开说一下。
重点关注在这个事务提交前,将 redo log 的写入拆成了两个步骤,prepare 和 commit,这就是"两阶段提交”。
为什么要采用两阶段提交呢?
实际上,两阶段提交是分布式系统常用的机制。MySQL使用了两阶段提交后,也是为了保证事务的持久性。Redo log 和bingo 有一个共同的数据字段,叫 XID,崩溃恢复的时候,会按顺序扫描 redo log。
- 假设在写入binlog前系统崩溃,那么数据库恢复后顺序扫描 redo log,碰到只有 parepare、而没有 commit 的 redo log,就拿着 XID 去 binlog 找对应的事务,而且binlog也没写入,所以事务就直接回滚了。
- 假设在写入binlog之后,事务提交前数据库崩溃,那么数据库恢复后顺序扫描 redo log,碰到既有 prepare、又有 commit 的 redo log,就直接提交,保证数据不丢失。
这个事务要往两个表中插入记录,插入数据的过程中,生成的日志都得先写入redo log buffer ,等到commit的时候,才真正把日志写到 redo log 文件。(当然,这里不绝对,因为redo log buffer可能因为其他原因*刷新到redo log)。
而为了确保每次日志都能写入日志文件,在每次将重做日志缓冲 写入 重做日志文件 后,InnoDB存储引擎都需要调用一次fsync操作,确保写入了磁盘。
对于redo log的持久化,可以如下图所示。
1)先写入redo log buffer,在蓝色区域。
2)写入redo log file,但是还没有fsync,这时候是处于黄色的位置,处于系统缓存。
3)调用fsync,真正写入磁盘。
为了控制 redo log 的写入策略,InnoDB 提供了 innodb_flush_log_at_trx_commit 参数,它有三种可能取值:
- 设置为 0 的时候,表示每次事务提交时都只是把 redo log 留在 redo log buffer 中 ;
- 设置为 1 的时候,表示每次事务提交时都将 redo log 直接持久化到磁盘;
- 设置为 2 的时候,表示每次事务提交时都只是把 redo log 写到 page cache。
binlog的写入和redo log一样,也是包括bingo cache和bingo file,同样跟上面的三色层次类似(当然,binlog是server层的,不是存储引擎层的),包括log buffer、文件系统page cache、hard disk。
写入page cache 和 fsync到disk 的时机,是由参数 sync_binlog 控制的:
- sync_binlog=0 的时候,表示每次提交事务都只 写入文件系统的page cache,不 fsync;
- sync_binlog=1 的时候,表示每次提交事务都会执行 fsync;
- sync_binlog=N(N>1) 的时候,表示每次提交事务都写入文件系统的page cache,但累积 N 个事务后才 fsync。(如果主机发生异常重启,会丢失最近 N 个事务的 binlog 日志)
通常我们说 MySQL 的“双 1”配置,指的就是 sync_binlog 和 innodb_flush_log_at_trx_commit 都设置成 1。也就是说,一个事务完整提交前,需要等待两次刷盘,一次是 redo log(prepare 阶段),一次是 binlog。
特别需要区分的是,redo log和binlog的不同。这也是经常在面试中可能会问到的两种日志的差异。
注意有这么几点:
- 产生位置不同。
redo log是innodb的存储引擎产生的,而binlog是数据库的server层实现的。换句话说,如果你使用MySQL,换其他存储引擎,那么可能没有redo log,但是还是会有binlog。
- 日志记录的内容形式不同。
binlog是一种逻辑日志,记录对应的SQL语句,而redo log记录了物理日志,是针对每个数据页的修改。
- 日志写入磁盘时间不同。
binlog只有在事务提交后完成一次写入,对于一个事物而言,在binlog中只有一条记录。而redo log在事务进行中不断被写入,而且是并发写入的,不是顺序写入的。
- 保存方式不同。
redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。“追加写”是指 binlog 文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。
3.原子性的实现
Undo log保证了事务的原子性。
在对数据库进行修改时,innoDB引擎除了会产生redo log,还会产生undo log。InnoDB实现回滚,靠的是undo log:当事务对数据库进行修改时,InnoDB会生成对应的undo log;如果事务执行失败导致事务需要回滚,就利用undo log中的信息将数据回滚到修改之前的样子。
有人认为undo log是redo log的逆过程,其实是不对的。两个日志文件其实都能看作是一种对数据的恢复操作,redo log恢复事务导致的数据页的修改,而undo log能够恢复数据记录到某个特定的版本。
所以redo log是一种物理日志(数据页的修改),而undo log是一种逻辑日志(数据记录)。
undo log还要另外一个重要作用,就是用于mvcc中,进行多版本控制,也就是实现事务隔离性的基础,当用户读取一行记录时,如果这个记录已接被其他事务占用,那么当前事务就可以通过undo读取之前的行版本信息,用来实现非锁定读取,就是“快照读”。(事务隔离性的问题,可以看我上一篇文章 跟面试官侃半小时MySQL事务隔离性,从基本概念深入到实现 )。
4.一致性的实现
就像一开始在定义的时候介绍的,事务的ACID性质不是完全正交的,尤其是一致性,我们可以认为原子性、持久性和隔离性都是为了实现事务的一致性。
当然,这里的一致性是指数据库层面的事务一致性。
如果说你在应用层面做一个操作,给转账者扣钱,没给接收者加钱,那么这个不一致跟事务的不一致是没有关系的,需要开发人员自己做业务逻辑一致性的保证。
看到这里了,原创不易,点个关注、点个赞吧,你最好看了~
知识碎片重新梳理,构建Java知识图谱:https://github.com/saigu/JavaKnowledgeGraph(历史文章查阅非常方便)
扫码关注我的公众号“阿丸笔记”,第一时间获取最新更新。同时可以免费获取海量Java技术栈电子书、各个大厂面试题。
跟面试官侃半小时MySQL事务,说完原子性、一致性、持久性的实现的更多相关文章
-
跟面试官侃半小时MySQL事务隔离性,从基本概念深入到实现
提到MySQL的事务,我相信对MySQL有了解的同学都能聊上几句,无论是面试求职,还是日常开发,MySQL的事务都跟我们息息相关. 而事务的ACID(即原子性Atomicity.一致性Consiste ...
-
面试官一口气问了MySQL事务、锁和MVCC,我
面试官:你是怎么理解InnoDB引擎中的事务的? 候选者:在我的理解下,事务可以使「一组操作」要么全部成功,要么全部失败 候选者:事务其目的是为了「保证数据最终的一致性」. 候选者:举个例子,我给你发 ...
-
面试官问你:MYSQL事务和隔离级别,该如何回答
一.事务 事务是由一组SQL语句组成的逻辑处理单元,是满足 ACID 特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚.事务具有以下4个属性,通常简称为事务 ...
-
【MySQL】面试官问我:MySQL如何实现无数据插入,有数据更新?我是这样回答的!
写在前面 马上就是金九银十的跳槽黄金期了,很多读者都开始出去面试了.这不,又一名读者出去面试被面试官问了一个MySQL的问题:向MySQL中插入数据,如何实现MySQL中没有当前id标识的数据时插入数 ...
-
一张图,让你和面试官聊一个小时的“Java内存模型”
如果面试官问你:你了解 Java 内存模型吗? 你就可以使用这张图,按照这张图中的顺序和面试官开聊,正常情况下,聊一个小时是差不多的,这个时候,对你的处境是非常有益的,因为面试官的时间不多了.
-
【Java】面试官灵魂拷问:if语句执行完else语句真的不会再执行吗?
写在前面 最近跳槽找工作的朋友确实不少,遇到的面试题也是千奇百怪,这不,一名读者朋友面试时,被面试官问到了一个直击灵魂的问题:if 语句执行完else语句真的不会再执行吗?这个奇葩的问题把这名读者问倒 ...
-
## 【分布式事务】面试官问我:MySQL中的XA事务崩溃了如何恢复??
写在前面 前段时间搭建了一套MySQL分布式数据库集群,数据库节点有12个,用来测试各种分布式事务方案的性能和优缺点.测试MySQL XA事务时,正当测试脚本向数据库中批量插入数据时,强制服务器断电! ...
-
【原创】面试官:谈谈你对mysql联合索引的认识?
引言 本文预计分为两个部分: (1)联合索引部分的基础知识 在这个部分,我们温习一下联合索引的基础 (2)联合索引部分的实战题 在这个部分,列举几个我认为算是实战中的代表题,挑出来说说. 正文 基础 ...
-
面试官突然问我MySQL存储过程,我竟然连基础都不会!(详细)
所有知识体系文章,GitHub已收录,欢迎Star!再次感谢,愿你早日进入大厂! GitHub地址: https://github.com/Ziphtracks/JavaLearningmanual ...
随机推荐
-
Oracle 10g安装教程
首先下载安装文件,打开后文件结构如图所示: 安装之前请关闭Windows防火墙并断开网络. xp系统下直接双击运行(本经验以XP系统安装为例进行讲述). 如果是在win7上安装,如图:在setup文件 ...
-
JavaScript学习02 基础语法
JavaScript学习02 基础语法 JavaScript中很多基础内容和Java中大体上基本一样,所以不需要再单独重复讲了,包括: 各种算术运算符.比较运算符.逻辑运算符: if else语句.s ...
-
sql 操作,
SELECT * FROM dbo.tbl_Web_Photos AS pt LEFT JOIN dbo.tbl_Web_Friends AS fd ON pt.user_email=fd.AddEm ...
-
UVA 12904 Load Balancing 暴力
Load Balancing Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/vi ...
-
Android开发之技术文章索引
Activity: 1.PreferenceActivity Fragment: 1.fragment中套用PagerSlidingTabStrip,切换底部时viewpager消失的解决 Widge ...
-
MySql按指定天数进行分组数据统计分析 1
这几天,在做数据统计,在对数据库数据进行统计过程中,有个需求就是要按照指定天数进行分组, 之前一直没有找到好的方法,就先取出数据,在程序中进行分组. 后发现,可以在SQL语句中实现按天数分组. 例: ...
-
leetcode first bad version python
# The isBadVersion API is already defined for you. # @param version, an integer # @return a bool # d ...
-
Twitter数据抓取的方法(三)
Scraping Tweets Directly from Twitters Search – Update Published August 1, 2015 Sorry for my delayed ...
-
Spring Boot 系列(三)属性配置&;自定义属性配置
在使用spring boot过程中,可以发现项目中只需要极少的配置就能完成相应的功能,这归功于spring boot中的模块化配置,在pom.xml中依赖的每个Starter都有默认配置,而这些默认配 ...
-
Python入门 (一)
本文是个人python学习笔记,学习资料为廖雪峰python教程,如需更多内容,请移步廖老师官方网站. 一 安装 官网下载安装包安装,安装好之后,在命令提示符输入python进入Python交互模式: ...