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 log
和binlog
内容决定回滚数据还是提交数据。
采用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的特性来实现, 如果我们写出违反约束的代码, 数据库是无法帮助我们实现一致性的。
评论
添加一条评论