点击上方 "编程技术圈"关注, 星标或置顶一起成长

后台回复“大礼包”有惊喜礼包!

日英文

Sometimes,God does not give you what you want,it is not because you do not deserve it but for the better.

有时候,上天没有给你想要的,不是因为你不配,而是你值得更好的。

每日掏心话

如果最美的发生在曾经,那么未来还要不要继续。事实上,那一个曾经占据过你生活的人不是别的,他是你的蓝天,你的阳光,你的空气。

责编:乐乐 | 来自:无名鼠辈链接:llc687.top/posts/数据库/mysql的acid

编程技术圈(ID:study_tech)第 1245 次推文

往日回顾:字节跳动涉代码抄袭被诉陪22.74亿,连错误的函数都搬?

     

   正文   

写在前面本文主要探讨MySQL InnoDB 引擎下ACID的实现原理,对于诸如什么是事务,隔离级别的含义等基础知识不做过多阐述。
ACIDMySQL 作为一个关系型数据库,以最常见的 InnoDB 引擎来说,是如何保证 ACID 的。
(Atomicity)原子性:事务是最小的执行单位,不允许分割。原子性确保动作要么全部完成,要么完全不起作用;(Consistency)一致性:执行事务前后,数据保持一致;(Isolation)隔离性:并发访问数据库时,一个事务不被其他事务所干扰。(Durability)持久性: 一个事务被提交之后。对数据库中数据的改变是持久的,即使数据库发生故障。隔离性先说说隔离性,首先是四种隔离级别。
不同的隔离级别是为了解决不同的问题。也就是脏读、幻读、不可重复读。
那么不同的隔离级别,隔离性是如何实现的,为什么不同事物间能够互不干扰?答案是 锁 和 MVCC。
锁先来说说锁, MySQL 有多少锁。
粒度从粒度上来说就是表锁、页锁、行锁。表锁有意向共享锁、意向排他锁、自增锁等。行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁,比如 MyISAM 引擎就不支持行锁。
行锁的种类在 InnoDB 事务中,行锁通过给索引上的索引项加锁来实现。这意味着只有通过索引条件检索数据,InnoDB才使用行级锁,否则将使用表锁。行级锁定同样分为两种类型:共享锁和排他锁,以及加锁前需要先获得的意向共享锁和意向排他锁。
共享锁:读锁,允许其他事务再加S锁,不允许其他事务再加X锁,即其他事务只读不可写。select...lock in share mode 加锁。排它锁:写锁,不允许其他事务再加S锁或者X锁。insert、update、delete、for update加锁。行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
行锁的实现算法Record Lock
单个行记录上的锁,总是会去锁住索引记录。
Gap Lock
间隙锁,想一下幻读的原因,其实就是行锁只能锁住行,但新插入记录这个动作,要更新的是记录之间的“间隙”。所以加入间隙锁来解决幻读。
Next-Key Lock
Gap Lock + Record Lock, 左开又闭。
锁之于隔离性大致介绍了下锁,可以看到。有了锁,当某事务正在写数据时,其他事务获取不到写锁,就无法写数据,一定程度上保证了事务间的隔离。但前面说,加了写锁,为什么其他事务也能读数据呢,不是获取不到读锁吗?
MVCC前面说到,有了锁,当前事务没有写锁就不能修改数据,但还是能读的,而且读的时候,即使该行数据其他事务已修改且提交,还是可以重复读到同样的值。这就是MVCC,多版本的并发控制,Multi-Version Concurrency Control。
版本链Innodb 中行记录的存储格式,有一些额外的字段:DATA_TRX_ID和DATA_ROLL_PTR。
DATA_TRX_ID:数据行版本号。用来标识最近对本行记录做修改的事务 id。DATA_ROLL_PTR:指向该行回滚段的指针。该行记录上所有旧版本,在 undo log 中都通过链表的形式组织。undo log : 记录数据被修改之前的日志,后面会详细说。ReadView在每一条 SQL 开始的时候被创建,有几个重要属性:
trx_ids: 当前系统活跃(未提交)事务版本号集合。low_limit_id: 创建当前 read view 时“当前系统最大事务版本号+1”。up_limit_id: 创建当前read view 时“系统正处于活跃事务最小版本号”creator_trx_id: 创建当前read view的事务版本号;开始查询现在开始查询,一个 select 过来了,找到了一行数据。
DATA_TRX_ID <up_limit_id :说明数据在当前事务之前就存在了,显示。DATA_TRX_ID >= low_limit_id:说明该数据是在当前read view 创建后才产生的,数据不显示。不显示怎么办,根据 DATA_ROLL_PTR 从 undo log 中找到历史版本,找不到就空。up_limit_id <DATA_TRX_ID <low_limit_id :就要看隔离级别了。RR 级别的幻读有了锁和 MVCC , 事务的隔离性得到解决。这里要引申一下,默认的 RR 的级别,解决了幻读吗?幻读通常针对的是INSERT, 不可重复度则针对UPDATE。
搜索公众号后端架构师后台回复“架构整洁”,获取一份惊喜礼包。
我们期望是
id  name
1   A
2   B
实际却是
id  name
1   B
2   B
其实在 MySQL 可重复读的隔离级别中并不是完全解决了幻读的问题,而是解决了读数据情况下的幻读问题。而对于修改的操作依旧存在幻读问题,就是说 MVCC 对于幻读的解决时不彻底的。
原子性接着说说原子性。前文有提到 undo log ,回滚日志。隔离性的MVCC其实就是依靠它来实现的,原子性也是。实现原子性的关键,是当事务回滚时能够撤销所有已经成功执行的sql语句。
当事务对数据库进行修改时,InnoDB会生成对应的 undo log;如果事务执行失败或调用了 rollback,导致事务需要回滚,便可以利用 undo log 中的信息将数据回滚到修改之前的样子。undo log 属于逻辑日志,它记录的是sql执行相关的信息。当发生回滚时,InnoDB 会根据 undo log 的内容做与之前相反的工作:
对于每个 insert,回滚时会执行 delete;对于每个 delete,回滚时会执行insert;对于每个 update,回滚时会执行一个相反的 update,把数据改回去。以update操作为例:当事务执行update时,其生成的undo log中会包含被修改行的主键(以便知道修改了哪些行)、修改了哪些列、这些列在修改前后的值等信息,回滚时便可以使用这些信息将数据还原到update之前的状态。
持久性Innnodb有很多 log,持久性靠的是 redo log。
一条SQL更新语句怎么运行持久性肯定和写有关,MySQL 里经常说到的 WAL 技术,WAL 的全称是 Write-Ahead Logging,它的关键点就是先写日志,再写磁盘。就像小店做生意,有个粉板,有个账本,来客了先写粉板,等不忙的时候再写账本。
redo logredo log 就是这个粉板,当有一条记录要更新时,InnoDB 引擎就会先把记录写到 redo log(并更新内存),这个时候更新就算完成了。在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候做,这就像打烊以后掌柜做的事。redo log 有两个特点
大小固定,循环写crash-safe对于redo log 是有两阶段的:commit 和 prepare 如果不使用“两阶段提交”,数据库的状态就有可能和用它的日志恢复出来的库的状态不一致. 好了,先到这里,看看另一个。
Buffer PoolInnoDB还提供了缓存,Buffer Pool 中包含了磁盘中部分数据页的映射,作为访问数据库的缓冲:
当读取数据时,会先从Buffer Pool中读取,如果Buffer Pool中没有,则从磁盘读取后放入Buffer Pool;当向数据库写入数据时,会首先写入Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中。Buffer Pool 的使用大大提高了读写数据的效率,但是也带了新的问题:如果MySQL宕机,而此时 Buffer Pool 中修改的数据还没有刷新到磁盘,就会导致数据的丢失,事务的持久性无法保证。
所以加入了 redo log。 当数据修改时,除了修改Buffer Pool中的数据,还会在redo log记录这次操作;
当事务提交时,会调用fsync接口对redo log进行刷盘。
如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复。
redo log采用的是WAL(Write-ahead logging,预写式日志),所有修改先写入日志,再更新到Buffer Pool,保证了数据不会因MySQL宕机而丢失,从而满足了持久性要求。而且这样做还有两个优点:
刷脏页是随机 IO,redo log 顺序 IO刷脏页以Page为单位,一个Page上的修改整页都要写;而redo log 只包含真正需要写入的,无效 IO 减少。binlog说到这,可能会疑问还有个 bin log 也是写操作并用于数据的恢复,有啥区别呢。
层次:redo log 是 innoDB 引擎特有的,server 层的叫 binlog(归档日志)内容:redolog 是物理日志,记录“在某个数据页上做了什么修改”;binlog 是逻辑日志,是语句的原始逻辑,如“给 ID=2 这一行的 c 字段加 1 ”写入:redolog 循环写且写入时机较多,binlog 追加且在事务提交时写入binlog 和 redo log对于语句 update T set c=c+1 where ID=2;
执行器先找引擎取 ID=2 这一行。ID 是主键,直接用树搜索找到。如果 ID = 2 这一行所在数据页就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,再返回。执行器拿到引擎给的行数据,把这个值加上 1,N+1,得到新的一行数据,再调用引擎接口写入这行新数据。引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log 里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,随时可以提交事务。执行器生成这个操作的 binlog,并把 binlog 写入磁盘。执行器调用引擎的提交事务接口,引擎把刚刚写入的 redo log 改成提交(commit)状态,更新完成为什么先写 redo log 呢 ?
先 redo 后 bin : binlog 丢失,少了一次更新,恢复后仍是0。先 bin 后 redo : 多了一次事务,恢复后是1。一致性一致性是事务追求的最终目标,前问所诉的原子性、持久性和隔离性,其实都是为了保证数据库状态的一致性。当然,上文都是数据库层面的保障,一致性的实现也需要应用层面进行保障。也就是你的业务,比如购买操作只扣除用户的余额,不减库存,肯定无法保证状态的一致。
总结MySQL 都很熟, ACID 也知道是个啥,但 MySQL 的 ACID 怎么实现的?有时候,就像你知道了有 undo log、redo log 但可能并不太清楚为什么有,当知道了设计的目的,了解起来就会更加清晰了。
参考MVCC 实现原理MySQL 中的锁MySQL 事务中 ACID 实现原理深入 MySQL 事务PS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!欢迎加入后端架构师交流群,在后台回复“学习”即可。最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。在这里,我为大家准备了一份2021年最新最全BAT等大厂Java面试经验总结。
别找了,想获取史上最简单的Java大厂面试题学习资料
扫下方二维码回复「面试」就好了猜你还想看
阿里、腾讯、百度、华为、京东最新面试题汇集
后端接口如何提高性能?程序员缺乏经验的 7 种表现还在写大量 if 来判断?试试用一个规则执行器来替代它嘿,你在看吗?

MySQL 是如何实现 ACID 的?相关推荐

  1. MySQL事务篇:ACID原则、事务隔离级别及事务机制原理剖析

    引言 众所周知,MySQL数据库的核心功能就是存储数据,通常是整个业务系统中最重要的一层,可谓是整个系统的"大本营",因此只要MySQL存在些许隐患问题,对于整个系统而言都是致命的 ...

  2. mysql数据库的事务 acid 隔离级别 脏读 脏写 幻读 不可重复读

    事务的四大特征 原子性(atomicity):要么全部提交(commit),要么全部回滚(rollback) 一致性(consistency):数据从一个合法状态转换成另一种合法状态 隔离性(isol ...

  3. mysql如何实现acid中的a_MySQL如何实现事务的ACID

    前言 最近在面试,有被问到,MySQL的InnoDB引擎是如何实现事务的,又或者说是如何实现ACID这几个特性的,当时没有答好,所以自己总结出来,记录一下. 事务的四大特性ACID 事务的四大特性AC ...

  4. Mysql.ACID

    前言 Mysql关系型数据库的ACID规则: A (Atomicity) 原子性: 事务(transaction)里的所有操作要么全部做完 C (Consistency) 一致性: 数据库要一直处于一 ...

  5. mysql 读提交,MySQL如何实现ACID ?

    写在前面 本文主要探讨MySQL InnoDB 引擎下ACID的实现原理,对于诸如什么是事务,隔离级别的含义等基础知识不做过多阐述. ACID MySQL 作为一个关系型数据库,以最常见的 InnoD ...

  6. mysql主要有什么问题_mysql问题

    什么是索引? 索引是一个单独的.物理的数据库结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单. 一个表的存储是由两部分组成的,一部分用来存放表的数据页面,另一 ...

  7. mysql事务机制_MySQL系列:事务机制

    一.MySQL并发访问控制 1.并发控制机制 (1)锁机制 资源竞争时候,多个线程表示多个用户会话:通过读写锁机制实现 读锁:共享锁,可以多个用户同时读取同一资源文件 写锁:独占锁,当一个用户对资源文 ...

  8. mysql四种事务隔离级别

    mysql事务并发问题 ACID什么的就不啰嗦了.mysql多个事务并发的时候,可能会出现如下问题: 1. 更新丢失 即两个事务同时更新某一条数据,后执行的更新操作会覆盖先执行的更新操作,导致先执行的 ...

  9. mysql四种输入_mysql四种事务隔离级别

    mysql事务并发问题 ACID什么的就不啰嗦了.mysql多个事务并发的时候,可能会出现如下问题: 1. 更新丢失 即两个事务同时更新某一条数据,后执行的更新操作会覆盖先执行的更新操作,导致先执行的 ...

最新文章

  1. AllUsers And SiteUsers
  2. C++在不使用任何算术运算符的情况下将两个数字相加(附完整源码)
  3. java 精灵线程_Java线程的状态分析
  4. Linux:守护进程详解及实现
  5. python OCR 图形识别
  6. 一旦有辞职念头就干不长了吗_如何理性而高效地辞职?
  7. Halcon 基本算子释义
  8. 常用的Linux操作命令
  9. python转换函数使用_Python基础学习之时间转换函数用法详解
  10. 微信unionId和openId
  11. Android串口调试工具ComAssistant下载
  12. 神仙代码静态测试工具 Helix QAC 2022.3中的新增功能
  13. win10护眼模式_这6个电脑操作技巧,会让你爱上Win10系统
  14. 抽象代数笔记-环、域、扩域、伽罗瓦理论
  15. 机器人导论 学习笔记2 - 运动学(D-H模型)
  16. Qt 网络聊天室项目
  17. GUARDED_BY(c) 和 PT_GUARDED_BY(c)
  18. 现货K线图知识之五:北坡炮兵并排跑
  19. MySQL数据查询---连接查询
  20. 区块链系统有服务器吗,区块链需要服务器吗

热门文章

  1. Linux 文件内容大小写转换
  2. 《精通引动APP测试实战:技术、工具和案例》---Android 开发环境搭建
  3. Launcher3 workspace 加载默认的布局
  4. DDOS(分布式拒绝服务)攻防实战演练
  5. 苹果app,Touch Album 私密相册强制消费,勒索消费者,一周50元,app降级到1.4.2之前 可解决
  6. Xmanager下载
  7. 访谈深圳汉捷研发管理咨询公司副总裁郭富才
  8. 分析抖音大V视频,可视化显示数据,看看大家都喜欢哪些视频?
  9. 快速理解AAC编码格式
  10. RTMP协议封装AAC(ADTS)格式详解