MySQL事务是什么,它就是一组数据库的操作,是访问数据库的程序单元,事务中可能包含一个或者多个 SQL 语句。这些SQL 语句要么都执行、要么都不执行。我们知道,在MySQL 中,有不同的存储引擎,有的存储引擎比如MyISAM 是不支持事务的,所以说MySQL 事务实际上是发生在 存储引擎部分

事务主要有四大特性,分别是原子性(Atomicity)、持久性(Consistency)、隔离性(Isolation)和 持久性(Durability)。它实际上是从四个方面来阐述MySQL 事务的特点,下面就分别来看MySQL 通过什么方式来实现这些特性。

一、原子性

1. 原子性定义

原子性就是指事务的不可分割性,对于一个事务而言,就是要么都执行,要么都不执行。在MySQL 中是通过回滚来实现,比如事务中的一个 SQL 语句失败了,那么该事务的所有SQL 语句必须都进行回滚,退回到事务前的状态。

2. InnoDB 中原子性的实现

上面说到,MySQL 中原子性是通过回滚的方式来实现,那么回滚是怎么实现的?这就涉及到MySQL 中的Undo 日志,原子性就是通过 Undo log 来实现的。

具体是Undo log 会在一个事务中,记录当前 SQL 语句的上一个语句成功的执行状态,如果在执行当前 SQL 语句失败后,就可以通过 Undo log 来回滚到 SQL 语句执行前的状态,这样就能保证事务的原子操作。举个例子,比如插入一条记录:insert into test values(1,'刘备','蜀')实际上得到的记录图如下,中间的 roll_pointer 是指向undo log的指针。

undo log 在事务提交后,undo log 日志也就会被回收。

二、持久性

1.持久性定义

持久性是指事务一旦提交,它对事务的改变是永久性的,哪怕系统发生了故障,也不会改变其提交的结果。持久性是通过 Redo log 来实现的。

2.InnoDB 中持久性的实现

在讲持久性之前,先介绍一下MySQL 中 Buffer pool,我们知道MySQL 数据是存储在磁盘中,为了实现快速读写数据,我们会在内存中设置一个 Buffer pool 缓冲池,数据库可以直接与 Buffer Pool 进行读取交互,定期再将 Buffer Pool 数据存储到磁盘中,这样会大大提高数据库的读写效率。

但是如果系统断电或者宕机,内存是无法保存信息的,而此时刚好Buffer Pool 数据没有同步到磁盘上,就会造成数据丢失。因此就需要 redo log 来对更新和修改操作进行记录,使得在系统重启时能够恢复到原来的状态。

Redo log 是一种预写式日志(write-Ahead Log),它记录的是在某个数据页上做了什么修改。当有记录需要更新时,InnoDB 引擎会先把记录写到 redo log 中,在系统空闲时,再将操作记录更新到磁盘中。redo log 结构如下图所示:

  • write pos 是当前记录的位置
  • checkpoint 当前要擦除的位置
  • write pos 和 check point 之间是 redo 内存区域中还空着的部分,用于记录新的操作。

redo log 只需要记录真正修改的部分,它的同步效率要比 buffer 同步数据快的多。那么 redo log 何时会同步到磁盘中去,主要是 innodb_flush_log_at_trx_commit这个参数的设置:

  • 0:表示当提交事务时,并不将缓冲区的 redo log 写入磁盘的日志文件,而是等待主线程每秒刷新
  • 1:在事务提交时将缓冲区的 redo log 同步写到磁盘中,保证一定会写入成功
  • 2:在事务提交时将缓冲区的redo 日志异步写入到磁盘中,即不能完全保证 commit 时肯定会写入到 redo 日志文件,只是有这个动作。

建议这个参数设置为1 ,同步写入磁盘中。

3.Binlog 和 Redo log

binlog 和 redo log 日志的区别

我们知道 redo log 是InnoDB 存储引擎的事务日志,那么对于 server 层是否也存在事务日志,答案是确定的,server 层的事务日志就是 binlog (归档日志)。为啥会出现两种事务日志,是因为最开始的 MySQL 中并没有 InnoDB 引擎,MySQL 自带的引擎是 MyISAM ,用的就是 binlog 日志来实现事务。那么两者具体有什么区别呢:

  • redo log 是InnoDB 引擎特有的,binlog 是 server 层实现,所有的存储引擎都可以使用
  • redo log 是物理日志,它存储的是在数据页上的修改;binlog 是逻辑日志,存储的是sql 语句的原始逻辑
  • redo log 空间是固定的,会使用完并覆盖原来的日志。binlog 可以追加写入,不会覆盖原来的日志

binlog 和 redo log 日志的两阶段提交

既然在MySQL 中存在两种日志,那么为了让两份日志之间的逻辑一致,就需要两阶段提交来实现这一任务。具体怎么实现的,我们以这个语句update T set c=c+1 where ID = 2来看:

  • 1.执行器先通过执行引擎查找 ID=2 这一行,如果数据在内存Buffer Pool 中直接返回。如果在磁盘中,则先从磁盘中读取到内存中,然后再返回。
  • 2.对取到的数据进行操作,将值加1后得到新的数据,再调用引擎写入数据,更新内存。
  • 3.同时将对数据页的修改记录到 redo log 中,这个时候 redo log 处于第一个阶段 prepare。
  • 4.执行器生成对于这个操作的 binlog ,并将 binlog 写入磁盘中
  • 5.执行器调用提交事务接口,把刚刚写入的 redo log 修改成 commit 状态,更新到此完成。

三、隔离性

1.隔离性定义

隔离性是指事务内部的操作与其他事务是隔离的,并发过程中的各个事务之间不能互相干扰。对于事务的操作,主要分成两种:读操作与写操作之间的影响、写操作与写操作之间的影响。

2.隔离性的实现

上面我们说到了事务之间的影响主要分成两个方面,那么MySQL 中是如何处理这两种情况的呢?

  • 写操作与写操作:就像 java 中的锁一样,通过锁来解决(MySQL 锁后续会出一篇文章详细介绍)
  • 写操作与读操作:主要是通过 MVCC 机制来解决(MVCC 后续会出一篇文章进行介绍)
    • 脏读
    • 不可重复读
    • 幻读

写操作与写操作的隔离实现

我们可以通过锁的方式,来保证同一时刻的一个数据的写操作只能被一个事务所执行。

在MySQL 中,根据加锁范围,大致可以分成三类:全局锁、表级锁和行级锁。 在一个事务修改数据前,需要获取对应的锁才能修改对应的数据。其他事务想要修改该数据,必须要等到之前的事务提交或回滚释放锁后,才能抢这个锁来修改数据。

锁的概况可以通过以下语句进行查询:

# 锁的概况
select * from information_schema.innodb_locks;
# InnoDB 整体状态,也包括锁的情况
show engine innodb status

写操作与读操作的隔离实现

为了保证性能,我们不能把所有操作都进行上锁,对于写操作和读操作,可以使用不加锁的方式来实现事务隔离。主要就是通过MySQL 中的 MVCC 机制来解决。

四、一致性

一致性的定义与实现

一致性的实现就是在前面三个特性实现的基础上而来的,没有前面三个特性的实现,也就达不到最后数据库事务的一致性。

参考资料

https://time.geekbang.org/column/article/68963

https://www.cnblogs.com/kismetv/p/10331633.html

MySQL 学习笔记(一)MySQL 事务的ACID特性的更多相关文章

  1. 吴裕雄--天生自然MySQL学习笔记:MySQL 事务

    MySQL 事务主要用于处理操作量大,复杂度高的数据.比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成 ...

  2. 吴裕雄--天生自然MySQL学习笔记:MySQL 运算符

    要介绍 MySQL 的运算符及运算符的优先级. MySQL 主要有以下几种运算符: 算术运算符 比较运算符 逻辑运算符 位运算符 算术运算符 MySQL 支持的算术运算符包括: 在除法运算和模运算中, ...

  3. 吴裕雄--天生自然MySQL学习笔记:MySQL 安装

    所有平台的 MySQL 下载地址为: MySQL 下载:https://dev.mysql.com/downloads/mysql/ 注意:安装过程我们需要通过开启管理员权限来安装,否则会由于权限不足 ...

  4. 吴裕雄--天生自然MySQL学习笔记:MySQL 导入数据

    1.mysql 命令导入 使用 mysql 命令导入语法格式为: mysql -u用户名 -p密码 < 要导入的数据库数据(runoob.sql) 实例: # mysql -uroot -p12 ...

  5. 吴裕雄--天生自然MySQL学习笔记:MySQL 处理重复数据

    有些 MySQL 数据表中可能存在重复的记录,有些情况允许重复数据的存在,但有时候我们也需要删除这些重复的数据. 防止表中出现重复数据 可以在 MySQL 数据表中设置指定的字段为 PRIMARY K ...

  6. 吴裕雄--天生自然MySQL学习笔记:MySQL 临时表

    MySQL 临时表在我们需要保存一些临时数据时是非常有用的.临时表只在当前连接可见,当关闭连接时,Mysql会自动删除表并释放所有空间. MySQL临时表只在当前连接可见,如果使用PHP脚本来创建My ...

  7. 吴裕雄--天生自然MySQL学习笔记:MySQL GROUP BY 语句

    GROUP BY 语句根据一个或多个列对结果集进行分组. 在分组的列上我们可以使用 COUNT, SUM, AVG,等函数. GROUP BY 语法 SELECT column_name, funct ...

  8. 吴裕雄--天生自然MySQL学习笔记:MySQL UNION 操作符

    MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中.多个 SELECT 语句会删除重复的数据. 语法 MySQL UNION 操作符语法格式: SELECT ...

  9. 吴裕雄--天生自然MySQL学习笔记:MySQL 连接

    使用mysql二进制方式连接 您可以使用MySQL二进制方式进入到mysql命令提示符下来连接MySQL数据库. 实例 以下是从命令行中连接mysql服务器的简单实例: [root@host]# my ...

  10. 吴裕雄--天生自然MySQL学习笔记:MySQL 管理

    启动及关闭 MySQL 服务器 Windows 系统下 在 Windows 系统下,打开命令窗口(cmd),进入 MySQL 安装目录的 bin 目录. 启动: cd c:/mysql/bin mys ...

随机推荐

  1. limit概述

    5.limit 5.1.limit是将查询结果集的一部分取出来,通常使用在分页查询中 分页作用是为了提高用户体验,可以一页一页翻页看 5.2.limit用法:(非常重要) 完整用法:limit sta ...

  2. PowerDotNet平台化软件架构设计与实现系列(12):HCRM人员管理平台

    技术服务于业务,良好的技术设计和实现能够大幅提升业务质量和效率. PowerDotNet已经形成了自己的开发风格,很多项目已被应用于生产环境,可行性可用性可靠性都得到了生产环境验证. 编程是非常讲究动 ...

  3. 洛谷P1002过河卒(60分)

    逻辑没问题,运行超时,得分60 写注释了,不多解释 import java.util.Scanner; public class D1 { static int a,b,c,d,con; //棋盘大小 ...

  4. %r和%s的区别

    理解%r和%s的区别 %r会重现所表达的对象,%s会将所有转成字符串 eg1: print('i am %s years old' % 22) print('i am %r years old' % ...

  5. Arduino+ESP32 之 驱动GC9A01圆形LCD(一),基于Arduino_GFX库

    最近买了一块圆形屏幕,驱动IC是GC9A01,自己参考淘宝给的stm32的驱动例程, 在ubuntu下使用IDF开发ESP32,也在windows的vscode内安装IDF开发ESP32,虽然都做到了 ...

  6. 013 Linux 搞懂「文件所属者更改及权限的赋予」从未如此简单(chmod、chgrp、chown)

    目录 01 一图详解「ls -l」 02 两种符号区分表示文件和目录 03 三种访问权限及表示 04 四种符号表示文件所属者用户 05 三个变更文件所属者及修改所属者权限的命令 06 工作实践命令举例 ...

  7. 远程连接MySQL报错1045解决方案

    MySQL远端操作步骤: 方法一: USE mysql: GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH ...

  8. Git修改提交历史中的作者及邮箱信息

    一.使用rebase 如图,红圈中提交的用户名及邮箱是需要改的,则需要复制需要改的提交记录的上一个记录hashcode,在本例中就是a0a891a48f92b51201042fccbe61ed1264 ...

  9. 《手把手教你》系列技巧篇(六十五)-java+ selenium自动化测试 - cookie -下篇(详细教程)

    1.简介 今天这一篇,宏哥主要讲解:利用WebDriver 提供可以读取.添加和删除cookie 信息的相关操作方法.验证浏览器中是否存在某个cookie.原因是:因为基于真实的cookie 的测试是 ...

  10. sublime中运行python时编码格式问题

      方案一在程序文件中以下三句 import sys reload(sys) sys.setdefaultencoding('utf8') 方案二在方案一不行的情况下,去除python的问题,subl ...