mysql事务
前言:MySQL系列之事务篇。
一、InnoDB的特点
todo
二、事务的实现原理
1、前情补充
在介绍ACID之前,我们需要补充一些InnoDB的相关知识。如下
1、刷盘
InnoDB是将一个表中数据存储到磁盘上的存储引擎,所以即使关机后重启我们的数据还是存在的,而真正处理数据的过程是发生在内存中的,所以需要把磁盘中的数据加载到内存中,如果是处理写入或修改请求的话,还需要把内存中的内容刷新到磁盘上。
而我们知道,读写磁盘的速度非常慢,和内存读写差了几个数量级,所以当我们想从表中获取某些记录时,难道InnoDB存储引擎需要一条一条的把记录从磁盘读出来么?
答案是否定的,那样会慢死,InnoDB采取的方式是:将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位。InnoDB中页大小一般为16kb(一般是操作系统页大小的整数倍),也就是一般情况下,一次最少从磁盘中读取16kb的内容到内存中,一次最少把16kb的内存刷新到磁盘中。
2、缓冲Buffer Pool
前面我们知道,读写数据的操作是通过内存,然后再到磁盘。但如果每次读写数据都需要磁盘IO,效率就会很低。为此,InnoDB提供了缓存Buffer Pool。
buffer pool中包含了磁盘中部分数据也的映射,作为访问数据库的缓冲:当从数据库读取数据时,会首先从Buffer Pool中读取,如果Buffer Pool中没有,则从磁盘读取后放入Buffer Pool;当想数据库写入数据时,会首先写入Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中(这一过程称为刷脏)。
3、三种日志
mysql里面的二进制bin log、重做日志redo log、回滚undo log至关重要。其中
1)功能比较
-
bin log:用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。还可用于数据库的基于时间点的还原。
-
redo log:确保事务的持久性。系统崩溃时,InnoDB根据此日志文件恢复尚未成功刷盘的数据(InnoDB特有日志)。
-
undo log:保证了数据的原子性、隔离性(要么全做,要么全不做)。保存了事务发生之前的数据版本,用于回滚,同时可以提供多版本并发控制下的读(MVCC),即一致性非锁定读。
2)内容比较
-
bin log:逻辑格式的日志,可以简单认为就是执行过的事务中的sql语句,但又不是sql语句这么简单,还包括了执行sql语句(增删改)的反向信息。
-
redo log:物理格式的日志,记录是物理数据页的修改信息。因此,当进行数据恢复时,可以不经过sql解析器而直接操作物理页。
-
undo log:逻辑格式的日志,在执行数据回滚时,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页上操作实现的,且undo log依赖redo log进行持久化。
3)问题汇总
- 逻辑格式、物理格式的日志,是根据什么确定的?
- 为什么undo依赖redo?
以上是三种日志文件一个大概比较,里面的一些细微之处需要好好体会,慢慢理解。
2、持久性实现原理
InnoDB引入了Buufer Pool有优化读写性能,但同时也带来了新的问题:如果Buufer Pool中修改的数据还未刷新到磁盘,此时MySQL宕机,就会导致数据的丢失,事务的持久性无法保证。
于是,就有了redo log。redo是物理日志,记录的是数据库中数据库中物理页的情况。
与Buufer Pool的定期刷盘不同(刷脏):
- 刷脏是随机IO,因为每次修改的数据位置随机;但写redo log是追加操作,属于顺序IO。
- 刷脏是以数据也为单位的,MySQL默认页大小为16kb,一个Page上一个小修改都要整页写入;而redo只包含真正需要写入的部分,无效IO大大减少。
数据落盘流程如下图所示

3、原子性实现原理
原子性指的是一个事务是一个不可分割的整体,要么全做,要么全不做。当事务失败时,需要回滚数据时,是依赖undo log来实现的。
undo log属于逻辑日志,我们可以这么认为,当delete一条记录时,undo log中会记录一条对应的insert 记录。当update一条记录时,也必然记录着一条与之相对应的反update记录,便于日后回滚数据。
这里解释下为什么undo log和bin log是逻辑日志,这是因为当进行数据回滚时,原物理地址可能会被新数据的写入而影响,且每台机器的物理地址各不相同,所以是逻辑日志,重写确定新的物理地址。至于redo为什么是物理日志,这是因为数据进行redo log写入时,此时在此机器的物理地址是确定的,但是为了性能考虑,暂时不写入实时数据罢了。
一般般帅