MySQL数据库:事务和ACID实现原理
一、什么是事务:
数据库的事务是并发控制的基本单位,是指逻辑上的一组操作,要么全部执行,要么全部不执行。
1、事务的特性:
(1)原子性:事务是一个不可分割的工作单元,事务里的操作要么都成功,要么都失败,如果事务执行失败,则需要进行回滚。
(2)隔离性:事务的所操作的数据在提交之前,对其他事务的可见程度。
(3)持久性:一旦事务提交,它对数据库中数据的改变就是永久的。
(4)一致性:事务不能破坏数据的完整性和业务的一致性。例如在转账时,不管事务成功还是失败,双方钱的总额不变。
二、事务ACID特性的实现原理:
1、原子性:
原子性是通过MySQL的回滚日志undo log来
实现的:当事务对数据库进行修改时,InnoDB会生成对应的undo log;
如果事务执行失败或调用了rollback
,导致事务需要回滚,便可以利用undo log
中的信息将数据回滚到修改之前的样子。
undo log
(回滚日志):是采用段(segment
)的方式来记录的,每个undo
操作在记录的时候占用一个undo log segment
。在数据更改操作时,记录了相对应的undo log的
目的在于:
- 保证数据的原子性,记录事务发生之前的一个版本,用于回滚;
- 通过mvcc +
undo log
实现Innodb事务可重复读和读已提交隔离级别。
2、隔离性:
隔离性是事务所操作的数据在提交之前,对其他事务的可见程度。
2.1、事务隔离级别:
为保证在并发环境下读取数据的完整性和一致性,数据库提供了四种事务隔离级别,隔离级别越高,越能保证数据的完整性和一致性,但对高并发性能影响也越大,执行效率越低。(四种隔离级别从上往下依次升高)
读未提交:允许事务在执行过程中,读取其他事务尚未提交的数据;
读已提交:允许事务在执行过程中读取其他事务已经提交的数据;
可重复读(默认级别):在同一个事务内,任意时刻的查询结果都是一致的;
读序列化:所有事务逐个依次执行,每次读都需要获取表级共享锁,读写会相互阻塞。
2.2、如果不考虑事务的隔离性,在事务并发的环境下,可能存在问题有:
(1)更新丢失:两个或多个事务操作相同的数据,然后基于选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题:最后的更新覆盖了其他事务所做的更新。
(2)脏读:指事务A正在访问数据,并且对数据进行了修改(事务未提交),这时,事务B也使用这个数据,后来事务A撤销回滚,并把修改后的数据恢复原值,B读到的数据就与数据库中的数据不一致,即B读到的数据是脏数据。
(3)不可重复读:在一个事务内,多次读取同一个数据,但是由于另一个事务在此期间对这个数据做了修改并提交,导致前后读取到的数据不一致;
(4)幻读:在一个事务中,先后两次进行读取相同的数据(一般是范围查询),但由于另一个事务新增或者删除了数据,导致前后两次结果不一致。
① 不可重复读和幻读的区别:
不可重复读侧重于读取到其他事务修改的数据,幻读侧重于读取到其他事务新增或者删除的数据。
② 可以采用锁机制来解决不可重复读和幻读:
对于不可重复读,只需对操作的数据添加行级锁,防止操作的数据发生变化;而对于幻读,需要添加表级锁,将整张表锁定,防止新增或者删除数据。
不同的事务隔离级别,在并发环境会存在不同的并发问题:
√:可能出现的情况 ×:不会出现该情况 |
脏读 |
不可重复读 |
幻读 |
读序列化 |
× |
× |
× |
可重复读 |
× |
× |
√ |
读已提交 |
× |
√ |
√ |
读未提交 |
√ |
√ |
√ |
2.3、事务隔离性的实现原理:
为了实现事务隔离,数据库延伸出了数据库锁,其中Innodb事务的隔离级别是由锁机制和MVVC(多版本并发控制)实现的:
2.3.1、Mysql锁机制:
MySQL锁机制的基本工作原理就是:事务在修改数据库之前,需要先获得相应的锁,获得锁的事务才可以修改数据;在该事务操作期间,这部分的数据是锁定,其他事务如果需要修改数据,需要等待当前事务提交或回滚后释放锁。(锁机制的更多说明可以参考另一篇博客:MySQL数据库:锁机制)
通过对InnoDB不同锁类型的特性分析,可以利用锁解决脏读、不可重复读、幻读:
排它锁解决脏读:在读已提交的隔离级别下,事务A只有在对数据修改时才加排它锁,但直到事务 commit 时才释放锁。因此,同时进行的事务B希望读取同一行数据时,会被事务A的排它锁堵塞,所以解决了脏读的问题
共享锁解决不可重复读:在可重复读的隔离级别下,除了执行读已提交的排它锁方式,还会在读取一行数据时,为这行数据添加共享锁直至事务 commit。例如,事务A读取ID=1这一行数据,然后为ID=1添加共享锁,事务B同时希望update ID=1,此时获取写锁失败,因此在事务A执行完之前,没有其他任何事务可以对ID=1这一行做修改,因此解决了重复读的问题
临键锁解决幻读
虽然共享锁和排它锁解决了事务隔离的并发问题,但锁会导致大量的堵塞,性能下降。某些时候会造成死锁,为了解决死锁,还要添加死锁探测机制,性能进一步下降,因此需要更高效的方式实现事务的隔离级别,也就是 MVCC 多版本并发控制。
2.3.2、Multiversion concurrency control
(MVCC
多版本并发控制):
InnoDB 的 MVCC 的实现思路是:对每一行数据用 undo log 记录多个版本,每个版本的数据可能都不相同,然后根据 事务ID 去寻找适合它的版本数据,从而实现不同事务之间的隔离性。MVCC 具体实现实现方式是在每行记录后面保存两个隐藏的列:
- DB_TRX_ID:标识当前数据属于哪个事务,每次提交事务,事务ID会自增,事务开始时会把该事务ID放到当前事务影响的行事务ID字段中,
- DB_ROLL_PTR:指向该行数据 undo log 的指针,undo log 日志文件保存了该行记录的所有版本数据,并在日志中通过链表形式组织
通过 MVCC,数据库可以使得事务的读取不需要很多读锁,提升了数据库的性能。当一个事务完成时,数据库会删除关于这条事务所有的 undo log,若未完成事务数据库崩溃则根据 undo log回滚,实现原子性。
MVCC只在 可重复度 和 读已提交 两个隔离级别下才会工作,其中,MVCC实质就是通过保存数据在某个时间点的快照来实现的。
- 读已提交:事务A执行每一条语句时,生成一份活跃事务表,根据这份表去获取数据,因此不会获取到脏数据(未提交事务引起的),但会有重复读问题(因为可以读取到commit 的事务数据)
- 可重复读:事务A只有在事务开始时才生成一份活跃事务表,因此不会读取到事务A执行中 commit 的其它事务引起的数据变更,也就不存在重复读问题。
在并发访问数据库时,对正在事务中的数据做MVCC多版本的管理,以避免写操作阻塞读操作,并且可以通过比较版本解决快照读方式的幻读问题,但对于当前读的幻读,MVCC并不能解决,需要通过临键锁来解决。
- 快照读:Innodb快照读,数据的读取将由 cache(原本数据) + undo(事务修改前的数据) 两部分组成
- 当前读:SQL读取的数据是最新版本。通过锁机制来保证读取的数据无法通过其他事务进行修改
在可重复读的隔离级别下,MVCC具体操作:
(1)SELECT操作:InnoDB遵循以下两个规则:
- 只查找数据行的事务ID小于或等于当前事务ID的版本,这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的记录。
- 行的删除版本要未被定义,读取到事务开始之前状态的版本,这可以确保事务读取到的行,在事务开始之前未被删除。只有同时满足的两者的记录,才能返回作为查询结果。
(2)INSERT:InnoDB为新插入的每一行保存当前事务编号作为行版本号。
(3)DELETE:InnoDB为删除的每一行保存当前事务编号作为行删除标识。
(4)UPDATE:InnoDB为插入一行新记录,保存当前事务编号作为行版本号,同时保存当前事务编号到原来的行作为行删除标识。
保存这两个额外系统版本号,使大多数读操作都可以不用加锁。这样设计使得读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行,不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。
3、持久性:
持久性的实现关键在于redo log日志,
在执行SQL时会保存已执行的SQL语句到一个指定的Log文件,当执行recovery
时重新执行redo log
记录的SQL操作。
3.1、redo log日志:
当向数据库写入数据时,执行过程会首先写入Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中(这一过程叫做刷盘),这整一过程称为redo log。redo log 分为:
- Buffer Pool内存中的日志缓冲(redo log buffer),该部分日志是易失性的;
- 磁盘上的重做日志文件(redo log file),该部分日志是持久的。
Buffer Pool的使用可以大大提高了读写数据的效率,但是也带了新的问题:如果MySQL宕机,而此时Buffer Pool中修改的数据在内存还没有刷新到磁盘,就会导致数据的丢失,事务的持久性无法保证。
为了确保事务的持久性,在当事务提交时,会调用fsync接口对redo log进行刷盘, (即redo log buffer
写日志到磁盘的redo log file
中 ),刷新频率由 innodb_flush_log_at_trx_commit
变量来控制的:
- 0: 每秒刷新缓冲池中的数据写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据 ;
- 1: 事务每次提交的时候,就把缓冲池中的数据刷新到磁盘中;
- 2:提交事务的时候,把缓冲池中的数据写入磁盘文件对应的 os cache 缓存里去,而不是直接进入磁盘文件。可能 1 秒后才会把 os cache 里的数据写入到磁盘文件里去。
4、一致性:
一致性指的是事务不能破坏数据的完整性和业务的一致性 :
数据的完整性: 实体完整性、列完整性(如字段的类型、大小、长度要符合要求)、外键约束等
业务的一致性:例如在银行转账时,不管事务成功还是失败,双方钱的总额不变。
那是如何保证数据一致性的?其实数据一致性是通过事务的原子性、持久性和隔离性来保证的:
- 原子性:语句要么全执行,要么全不执行,是事务最核心的特性,事务本身就是以原子性来定义的;主要基于undo log实现
- 持久性:保证事务提交后不会因为宕机等原因导致数据丢失;主要基于redo log实现
- 隔离性:保证事务执行尽可能不受其他事务影响;InnoDB默认的隔离级别是RR,RR的实现主要基于锁机制(包含next-key lock)、MVCC(包括数据的隐藏列、基于undo log的版本链、ReadView)
MySQL数据库:事务和ACID实现原理相关推荐
- mysql 事物的持久性是指_详解MySQL中事务的持久性实现原理
前言 说到数据库事务,大家脑子里一定很容易蹦出一堆事务的相关知识,如事务的ACID特性,隔离级别,解决的问题(脏读,不可重复读,幻读)等等,但是可能很少有人真正的清楚事务的这些特性又是怎么实现的,为什 ...
- MySQL学习-MySQL数据库事务
MySQL数据库事务 1.事务概述 1.什么是事务? 2.和事务相关的语句只有:**DML语句.(insert delete update)** 3.假设所有的业务都能使用1条DML语句搞定,还需要事 ...
- MySQL数据库事务的四大特性
MySQL数据库事务的四大特性以及事务的隔离级别_l1394049664的博客-CSDN博客_mysql数据库事务 深入学习MySQL事务:ACID特性的实现原理 - 编程迷思 - 博客园
- 15张图呈现数据库事务背后的并发原理
本文分享自华为云社区<将数据库9种锁.3种读.4种隔离级别一次性串联起来,用15张图呈现背后数据库事务背后的并发原理>,作者: breakDawn. 前段时间开发时,正好遇到了2个进程同时 ...
- MySQL数据库事务、mybatis框架、spring框架、springmvc框架、永和大王门店管理系统(框架第二部分)
第十二章 MySQL数据库事务 一. 事务及四大特性 1.什么是事务 数据库事务(Database Transaction),是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行 ...
- mysql数据库事务隔离级别演示
mysql数据库事务隔离级别演示 关键词: 一.基本概念 二.事务的四个特性(ACID) 三.事务的用法 3.1 相关命令 3.2 使用步骤 四.数据库的隔离级别 五.示例演示(每组事务结束手动com ...
- 数据库事务的ACID特性及含义
数据库事务的ACID特性及含义 1.原子性(Atomic) 一个事务被视为一个不可分割的最小工作单元,这个事务里的所有操作要么全部成功执行,要么全都不执行,不能只执行其中的一部分操作.实现事务的原子性 ...
- 概述MySQL数据库---事务隔离级别
同一个应用程序中的多个事务或不同应用程序中的多个事务在同一个数据集上并发执行时, 可能会出现许多意外的问题,事务并发处理可能引起的问题可分为如下三种类型: 脏读(Drity Read): 已知有两个事 ...
- 数据库事务的ACID及隔离级别
文章目录 ACID 概念 四大特性 并发控制 隔离级别 串行化 可重复读 提交读 未提交读 默认隔离级别 读现象举例 脏读 不可重复读 幻读 隔离级别 VS 读现象 隔离级别 VS 锁持续时间 ACI ...
最新文章
- 苹果隐藏应用_使用iMazing导出苹果设备中的录音文件
- 「Ubuntu」仓库 “https://mirrors.tuna.tsinghua.edu.cn/ubuntu focal Release” 没有 Release 文件。
- js获取Json对象的长度
- android 新闻功能列表,android根据提供的接口获取新闻列表
- tp5 html获取get,tp5获取请求参数
- 使用X-shell管理员root连接ubuntu17.10服务器拒绝密码的一个失误!
- 最详细!!!软考:初级程序员—思维导图
- 网页鼠标指针源码 小樱茉莉Q版鼠标指针
- linux 制作分区镜像img文件
- 转载 | 各种数据库JDBC下载
- 陀螺产业区块链第九季 | 如何用区块链搭建营销激励模型?
- 本地局域网HTTPS解决方案 CA证书
- C++中using的四大用法总结
- 伯克利创造出“可看到未来”的机器人,能帮助无人驾驶预测事故
- python数据分析-pandas学习
- 人生新的开始,组建大数据公司
- 集五福开始了 | 如何用5分钟集满五福
- centeros7 安装node
- java 项目 q a 表设计_《JAVA程序设计项目案例训练》期末试卷(A卷)..doc
- 基于gin框架的较为通用的web脚手架---CLD分层理念
热门文章
- 给定一个投资组合的收益序列,以沪深300作为参照,分解该投资组合的α和β
- Graphviz使用
- django连接数据库和数据迁移
- mysql数据库简单介绍_数据库的简单介绍
- 从ICLR 2022看什么是好的图神经网络?
- 医学影像中用 python 读取 nrrd 文件、nrrd转nii、nrrd转h5
- Java动态代理的两种实现方法:JDK动态代理和CGLIB动态代理
- Tomcat【环境搭建 01】安装包版本说明+安装+参数配置+启动(JDK11+最新版apache-tomcat-10.0.12)
- linux 进程死循环,Linux下如何处理一次用户态进程死循环问题
- 川崎焊接机器人编程实例_机器人现场编程-川崎机器人示教-综合命令.pptx