MySQL事务的ACID实现原理

浏览量1925

MySQL事务的ACID实现原理

事务是MySQL等关系型数据库区别于NoSQL的重要方面,是保证数据一致性的重要手段。

本文将着重讲解ACID实现的思路,涉及的具体实现不会细讲,读者可另行搜索。

ACID特性

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

其实事务的四个特性是衡量事务的四个维度而不是必须的实现,现实情况可结合性能和需求取舍

以隔离性为例,完全的隔离性需要选取Mysql的SERIALIZABLE 的隔离级别, 但是Mysql默认的隔离级别是REPEATABLE-READ, 是一个隔离性的完整程度与性能综合考量下比较合适的一个结果, 也是大多数公司选取的一个隔离级别

原子性

实现原理: undo log

undo log名为回滚日志,是实现原子性的关键,当事务回滚时能够撤销所有已经成功执行的SQL语句,他需要记录你要回滚的相应日志信息。

例如一个新增操作对应一个删除操作, 一个更新操作对应一个反向的更新操作, 一个删除操作对应...

undo log记录了这些回滚需要的信息,当事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。

持久性

实现原理: redo log

Mysql是先把磁盘上的数据加载到内存中,在内存中对数据进行修改,再刷回磁盘上。但是如果此时突然宕机,内存中的数据就会丢失。

怎么解决这个问题?

其实最简单的方式就是直接把修改写入磁盘, 但是这样做存在两个问题:

  • 数据库的写操作大概率是随机写, 如果一次只修改一个页, 会造成磁盘资源的大量浪费, 降低数据库性能
  • 一个事务可能涉及多个数据页的修改, 在事务执行期间直接写盘也会造成事务响应速度比较慢

但是,采用redo log就可以解决上面的问题。当做数据修改的时候,不仅在内存中操作,还会在redo log中记录这次操作。当事务提交的时候,会将redo log日志进行刷盘(redo log一部分在内存中,一部分在磁盘上)。当数据库宕机重启的时候,会将redo log中的内容恢复到数据库中,再根据undo logbinlog内容决定回滚数据还是提交数据。

采用redo log的好处?

其实好处就是将redo log进行刷盘比对数据页刷盘效率高,具体表现如下

  • redo log体积小,毕竟只记录了哪一页修改了啥,因此体积小,刷盘快。
  • redo log是一直往末尾进行追加,属于顺序IO。效率显然比随机IO来的快。
redo log与binlog的区别
  • 作用不同:redo log是crash safe的,保证MySQL宕机也不会影响持久性;binlog是用于point-in-time recovery的,保证服务器可以基于时间点恢复数据,此外binlog还用于主从复制。
  • 层次不同:redo log是InnoDB存储引擎实现的,而binlog是MySQL的服务器层(可以参考文章前面对MySQL逻辑架构的介绍)实现的,同时支持InnoDB和其他存储引擎。
  • 内容不同:redo log是物理日志,内容基于磁盘的Page;binlog的内容是二进制的,根据binlog_format参数的不同,可能基于sql语句、基于数据本身或者二者的混合。
  • 写入时机不同:binlog在事务提交时写入;redo log的写入时机相对多元:

隔离性

实现原理: 锁和MVCC(InnoDB)

数据库隔离性也是一个老生常谈的问题了

隔离性相关的内容可以参考我之前的博文 MySQL锁与事务

一致性

实现原理: AID

从数据库层面,数据库通过原子性、隔离性、持久性来保证一致性。也就是说ACID四大特性之中,一致性是目的,原子性、隔离性、持久性是手段,是为了保证一致性,数据库提供的手段。数据库必须要实现AID三大特性,才有可能实现一致性。例如,原子性无法保证,显然一致性也无法保证。

数据库的一致性需要我们程序员在写代码是利用AID的特性来实现, 如果我们写出违反约束的代码, 数据库是无法帮助我们实现一致性的。

评论

添加一条评论