事物与持久化_跟面试官侃半小时MySQL事务,说完原子性、一致性、持久性的实现...

提到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中也扮演重要角色,有兴趣的同学可以参考xxxxx)。这样才能保证断电或宕机等情况发生后,已提交的事务不会丢失,这个能力称为 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;

这个事务的写入过程实际拆解如下:

dceb63aa8e51ff9635ec4e734697d6ff.png

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的持久化,可以如下图所示。

5a9fdbb57cac04d9fa6da55b7a2273f0.png

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在事务进行中不断被写入,而且是并发写入的,不是顺序写入的。

e4b9f57063c44ebe1c9583bf6a5e59a1.png
  • 保存方式不同。

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技术栈电子书 和 大厂面试题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/526348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cookie里面用到的关键字_晓龙吊打面试官系列:synchronized关键字入门(同步方法与同步代码块)...

文章目录一、 线程安全问题二、synchronized简介1) 原子性2) 可见性3) 有序性4)可重入1. 什么是synchronized2.什么是同步3.synchronized的特性4.synchronized的实现原理(了解即可)三、synchronized的用法1. 同步方法2. 同步代码块四、对象锁和类锁1)对象锁2)类锁1.对象锁的探索…

mysql 函数返回查询结果_MySQL数据库中常用查询函数简介

MYSQL中的常用函数count(*)---相当于统计表的行数,在统计结果的时候,不会忽略列值为NULL的记录。 select count(*) from yinxiong;Count(列名)表示统计此列当中总行数(不计算null所在的行)Count(distinct 列名&#xf…

属性值动态调整_这可能是你见过最牛的CAD粗糙度动态块了!

好课推荐:零基础CAD:点我CAD家装:点我 周站长CAD:点我CAD机械:点我revit教程:点我CAD建筑:点我CAD三维:点我全屋定制:点我 ps教程:点我苹果版CAD:点我 3dmax教…

bootstrap mysql源码_Django+Bootstrap+Mysql 搭建个人博客 (六)

6.1.comments插件(1)安装pip install django-contrib-comments(02)settingsINSTALLED_APPS [django.contrib.sites,django_comments,]SITE_ID 1(3)website/urlurl(r^comments/, include(django_comments.urls)),(4)修改源码django_comments/abstracts.py第36行原代码site mode…

mysql 查看索引 命令_MySQL命令篇之库、表、索引、用户、视图及SELECT查询

大纲一、库管理二、表管理三、索引管理四、用户管理五、视图管理六、SELECT查询一、库管理(1)、创建数据库CREATE DATABASE db_name [CHARACTER SET [] charset_name] [COLLATE [] collation_name];mysql> CREATE DATABASE IF NOT EXISTS testdb CHARACTER SET gbk COLLATE …

mysql 数据修改记录日志_mysql对数据的更新操作记录在哪个日志中?

mysql对数据的更新操作记录在通用查询日志和二进制日志中。通用查询日志用来记录用户的所有操作,包括启动和关闭 MySQL 服务、更新语句和查询语句等;二进制日志会以二进制的形式记录数据库的各种操作,但不记录查询语句。(推荐教程&#xff1a…

mysql insert 二进制_MYSQL 插入二进制数的 2 种方法。

方法 1、insert into TableName set column ;方法 2、insert into TableName .... values(.....);------------------------------------------------------------------------------------------------------------------------------------------create table T(x bit(8));方…

mysql怎么分组查询所有数据库_Mysql-4 分组查询与子查询

1、查询结果的分组操作a、分组允许把数据分为多个组,以便能对每个组进行聚集计算b、分组是在select语句的group by 子句中建立的注意:group by 只是创建分组,但并不保证分组里面的数据的排列顺序,需要使用order by 子句对分组里面…

mysql update upper_MySQL数据处理函数upper、abs、date

1. 数据处理函数文本处理函数upper()转换大写函数SQL> select vend_name, upper(vend_name) as vend_name_upcase from vendors order by vend_name;soundex()发音类似函数SQL> select cust_name, cust_contact from customers where cust_contact Y. Lie;SQL> selec…

java 获取类方法_Java之反射机制三:获取类的方法

一.实体类BigDog.javapackage reflex;public class BigDog extends Dog {private Integer age;public String name;public BigDog(){}private void getDog(){}private BigDog(Integer age, String name) {this.age age;this.name name;}public String getName() {return name…

java语言50到100之间素数和_用JAVA语言编写一程序,求100以内的所有素数

满意答案fdewj5902017.02.13采纳率&#xff1a;40% 等级&#xff1a;9已帮助&#xff1a;316人12345678910111213141516171819public static void main(String[] args) { for (int i 2; i < 100; i) { int temp (int) Math.sqrt(i); …

java矩阵面积_Java基础 矩阵面积

提供 数据结构与算法题目 的平台是LintCode&#xff0c;参考链接是&#xff1a;http://www.lintcode.com/zh-cn/问题描述&#xff1a;参考代码&#xff1a;public class Rectangle {/** Define two public attributes width and height of type int.*/// write your code herep…

java判断线程是否wait_Java并发编程之线程间通讯(上)wait/notify机制

线程间通信如果一个线程从头到尾执行完也不和别的线程打交道的话&#xff0c;那就不会有各种安全性问题了。但是协作越来越成为社会发展的大势&#xff0c;一个大任务拆成若干个小任务之后&#xff0c;各个小任务之间可能也需要相互协作最终才能执行完整个大任务。所以各个线程…

python土味情话_Python 将土味情话语录设置为桌面壁纸

本文编写于 128 天前&#xff0c;最后修改于 128 天前&#xff0c;其中某些信息可能已经过时。41041-3yfokd0irbe.png38220-tlrmwji3zwo.pngimport osimport tempfileimport timeimport requestsimport win32apiimport win32conimport win32guifrom PIL import Image, ImageDra…

Day70力扣打卡

打卡记录 收集足够苹果的最小花园周长&#xff08;找规律 二分&#xff09; 链接 class Solution:def minimumPerimeter(self, neededApples: int) -> int:l, r 1, 10 ** 5while l < r:mid (l r) >> 1if 2 * (2 * (mid ** 3) 3 * (mid ** 2) mid) > nee…

java计数器策略模式_java设计模式(二十一)--策略模式

对于策略模式,我在很多面试题上看到过考察这一类的问题,这种模式也的确比较好用。 我感觉这种模式就是将不同实现的方法放到一个接口中,然后通过实现这个接口来实现不同的运行结果,这种模式有三部分构成: 策略接口 策略实现类 策略作用类(使用策略的类) 网络上的专业解释:此模式…

linux setuid函数_setuid函数解析

在讨论这个setuid函数之前&#xff0c;我们首先要了解的一个东西就是内核为每个进程维护的三个UID值。这三个UID分别是实际用户ID(real uid)、有效用户ID(effective uid)、保存的设置用户ID(saved set-user-ID)。首先说这个实际用户ID&#xff0c;就是我们当前以哪个用户登录了…

java中asl_带你认识绕不开的ASLR

微软从windows vista/windows server 2008(kernel version 6.0)开始采用ASLR技术&#xff0c;主要目的是为了防止缓冲区溢出ASLR技术会使PE文件每次加载到内存的起始地址随机变化&#xff0c;并且进程的栈和堆的起始地址也会随机改变。ASLR(Address space layout randomization…

Java 捕获 mybatis异常_3 springboot集成mybatis和全局异常捕获

mybatis有两种方式&#xff0c;一种是基于XML&#xff0c;一种是基于注解springboot集成mybatis首先先创建表&#xff0c;这里都简化了DROP TABLE IF EXISTS user;CREATE TABLE user (id int(11) NOT NULL auto_increment,username varchar(255) default NULL,PRIMARY KEY (id)…

java applet 访问文件_使用JavaApplet访问数据库

使用Java Applet访问数据库学习任何的程序语言&#xff0c;当然都得与数据库&#xff0c;Java刚刚诞生的时候&#xff0c;对数据库的支持并不是很好&#xff0c;经过这几年的发展&#xff0c;它对数据库的支持也已经完全达到了成熟的境地。由于这里主要是介绍Java Applet小程序…