写点什么

MySQL 事务 ACID 原理

作者:红袖添香
  • 2023-08-08
    北京
  • 本文字数:1473 字

    阅读完需:约 5 分钟

MySQL事务ACID原理

事务的四大特性(ACID)


  1. 原子性(atomicity):一个事务必须视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。

  2. 一致性(consistency):一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

  3. 隔离性(isolation):一个事务所做的修改在最终提交以前,对其他事务是不可见的。多个事务并发执行的时候,事务内部的操作与其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

  4. 持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。


MySQL 怎么保证一致性的?


数据库层面,数据库通过原子性、隔离性、持久性来保证一致性。也就是说 ACID 四大特性之中,C (一致性) 是目的,A (原子性)、I (隔离性)、D (持久性) 是手段,是为了保证一致性,数据库提供的手段。数据库必须要实现 AID 三大特性,才有可能实现一致性。


应用层面,通过代码判断数据库数据是否有效,然后决定回滚还是提交数据。但如果事务里故意写出违反约束的代码,一致性还是无法保证的。例如,你在转账的例子中,你的代码里故意不给 B 账户加钱,那一致性还是无法保证。因此,还必须从应用层角度考虑。


MySQL 怎么保证原子性的?


利用 Innodb 的 undo log。undo log 名为回滚日志,是实现原子性的关键,当事务回滚时能够撤销所有已经成功执行的 sql 语句,他需要记录你要回滚的相应日志信息。例如:(1) 当你 delete 一条数据的时候,就需要记录这条数据的信息,回滚的时候,insert 这条旧数据(2) 当你 update 一条数据的时候,就需要记录之前的旧值,回滚的时候,根据旧值执行 update 操作(3) 当年 insert 一条数据的时候,就需要这条记录的主键,回滚的时候,根据主键执行 delete 操作 undo log 记录了这些回滚需要的信息


MySQL 怎么保证持久性的?


利用 Innodb 的 redo log(重做日志)。MySQL 是先把磁盘上的数据加载到内存中,在内存中对数据进行修改,再刷回磁盘上。如果此时突然宕机,内存中的数据就会丢失。怎么解决这个问题?简单啊,事务提交前直接把数据写入磁盘就行啊。这么做有什么问题?只修改一个页面里的一个字节,就要将整个页面刷入磁盘,太浪费资源了。毕竟一个页面 16kb 大小,你只改其中一点点东西,就要将 16kb 的内容刷入磁盘,听着也不合理。毕竟一个事务里的 SQL 可能牵涉到多个数据页的修改,而这些数据页可能不是相邻的,也就是属于随机 IO。显然操作随机 IO,速度会比较慢。采用 redo log 解决上面的问题。当做数据修改的时候,不仅在内存中操作,还会在 redo log 中记录这次操作。当事务提交的时候,会将 redo log 日志进行刷盘 (redo log 一部分在内存中,一部分在磁盘上)。当数据库宕机重启的时候,会将 redo log 中的内容恢复到数据库中,再根据 undo log 和 binlog 内容决定回滚数据还是提交数据。


采用 redo log 的好处?redo log 进行刷盘比对数据页刷盘效率高,具体表现如下:redo log 体积小,毕竟只记录了哪一页修改了啥,因此体积小,刷盘快。redo log 是一直往末尾进行追加,属于顺序 IO。效率显然比随机 IO 来的快。


MySQL 怎么保证隔离性的?


利用的是锁和 MVCC 机制。MVCC, 即多版本并发控制 (Multi Version Concurrency Control), 一个行记录数据有多个版本对快照数据,这些快照数据在 undo log 中。 如果一个事务读取的行正在做 delete 或者 update 操作,读取操作不会等行上的锁释放,而是读取该行的快照版本。


发布于: 刚刚阅读数: 4
用户头像

红袖添香

关注

大雨落幽燕,白浪滔天 2018-08-10 加入

还未添加个人简介

评论

发布
暂无评论
MySQL事务ACID原理_MySQL_红袖添香_InfoQ写作社区