MySQL 主要是通过: 锁、Redo Log、Undo Log、MVCC
来实现事务
-
事务的隔离性利用锁机制实现
-
原子性、一致性和持久性由事务的 redo 日志和undo 日志来保证。
-
Redo Log
(重做日志):记录事务对数据库的所有修改,在崩溃时恢复未提交的更改,保证事务的持久性 -
Undo Log
(回滚日志),保存数据的历史版本,用于事务的回滚。用来保证事务的原子性、一致性
-
-
MVCC(多版本并发控制),满足了非锁定读的需求,提高了并发度,实现了读已提交,可重复读级别的 事务隔离性。
redo日志
作用
在内存中修改完数据后
更新数据记录到redo的磁盘日志中,最后在同步数据回磁盘,确保宕机时能恢复,保证事务的持久性
-
redo日志占用的空间很小且降低了刷盘频率
-
redo日志是顺序写入磁盘的,效率高
-
事务执行过程中,redo log
不断记录
redo log 是存引擎层产生的,而binlog是数据库层
产生的,假设一个事务,对表做了10万次记录插入,在这个过程中会一直往redo log中顺序记录
,而binlog不会记录,直到这个事务提交,才会一次性写到bin log中
组成
Redo log可以简单分为以下两个部分:redo_log_buffer、redo_log_file
-
重做日志的缓冲 (redo_log_buffer)
,保存在内存中,是易失的 -
重做日志文件 (redo_log_file)
,保存在硬盘中,是持久的。
在服务器启动时就向操作系统申请了一大片称之为redo log bufer的连续内存
空间,即redo日志缓冲区。被划分成若干个连续的redo log block
。一个redo log block占用512字节
大小。
参数设置:innodb_log_buffer_size
:
redo log buffer 大小,默认 16M
,最大值是4096M,最小值为1M
mysql> show variables like '%innodb_log_buffer_size%';
+------------------------+----------+
| Variable_name | Value |
+------------------------+----------+
| innodb_log_buffer_size | 16777216 |
+------------------------+----------+
流程
以一个更新事务为例,redo log
流转过程,如下图所示:
redolog刷盘策略⭐
首先redo log会实时同步到redo_log_buffer
,之后以 一定的频率
刷入到真正的redo_log_file
中。
这里的一定频率怎么看待呢?这就是我们要说的刷盘策略
-
注意:redo_log_buffer刷盘到redo_log_file的过程并
不是真正的刷到磁盘中去
,只是刷入到文件系统缓存(page_cache)
中去,真正的写入会交给系统
自己来决定(比如page cache足够大了) -
所以对于InnoDB,如果交给系统来同步,如果系统宕机,那么数据也丢失了
针对这种情况,InnoDB给出 innodb_flush_log_at_trx_commit
参数,该参数控制提交事务时,刷盘到redo_log_file中的三种策略
-
设置为0
:表示每次事务提交时不进行刷盘操作。(通过系统默认master thread每隔1s进行一次重做日志的同步)
-
设置为1
:表示每次事务提交时都将进行同步,刷盘操作( 默认值 )
-
设置为2
:每次事务
提交时
都只把redo_log_buffer
内容写入page_cache
(文件系统的缓存),不进行同步。由os自己决定什么时候同步到磁盘文件
SET GLOBAL innodb_flush_log_at_trx_commit = 1;
此外,InnoDB 存储引擎有一个后台线程
,每隔1 秒,就会把redo_log_buffer
中的内容写到文件系统缓存(page cache),然后调用刷盘操作
-
其次,当
redo_log_buffer
占用空间到 innnodb_buffer_size(默认16M)的一半时,也会主动刷盘 -
当参数设置为1时,只要事务提交成功,就一定会存在
redo.file
中 -
若事务执行期间mysql挂了,但redo.file通过后台线程自动刷盘保存了部分开始事务后的一些操作,重启后InnoDB 利用undo回滚日志决定是否回滚 或者继续执行事务
undo日志
undo log
是事务原子性
的保证。在事务中更新数据的 前置操作
其实是要先写入一个 undo log
,记录事务每一次修改的反向操作,便于回滚
作用
因为原子性 ,即事务的操作要么全部完成,要么什么也不做。假如执行到一半出现错误,就可以利用undo log
回滚数据
-
作用1:回滚数据
只是将数据库逻辑层面上恢复到原来的样子,只能弥补,如一些物理上的结构修改,无法回滚到之前的状态,比如undo日志中是逻辑删除
-
作用2:MVCC多版本并发控制
MVCC的实现是通过undo log来完成的。当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可以通过undo读取之前的行版本信息,以此实现非锁定读取
组成
①回滚段与undo页
InnoDB对undo log的管理采用段的方式,也就是 回滚段(rollback segment)
。每个回滚段记录了1024 个 undo log segment
,而在每个undo log segment
段中进行 undo页
的申请。
undo页被设计为可以重用
,即当事务提交后,并不会立即删除undo页,会放到链表中,判断其空间是否小于3/4
,小于则可以重用,但是因为重用,所以undo页中可能混杂其他事务的undo log,重用的事务记录在其之后
②回滚段与事务
③回滚段中的数据分类
生命周期
详细生成过程
当执行INSERT时:
begin;
INSERT INTO user (name) VALUES ("tom");
当执行UPDATE时:
begin;
UPDATE user (name) to ("Sun");
UPDATE user SET id=2 WHERE id=1; #删除id=1的数据,并把id=2的数据覆盖
undo log是如何回滚的?
-
undo no 0:记录的是 插入tom前的状态,即不存在
-
undo no 1:记录的数据是tom
-
undo no 2:记录的数据是Sun
-
undo no 3:记录的是id=1 时的数据
那么假设要回滚
==>通过3的日志把id=2的数据删除==>通过2的日志把id=1的数据的deletemark还原成0
==>通过undo no=1的日志把还原成Tom==>通过undo no=0的日志把id=1的数据删除
小结
先找是否有加载对应的BufferPool有就使用没有就加载读取 ----> 写入UndoLog
—>操作执行数据 —> 写入RedoLogBuffer内存
----> 写入RedoLog到磁盘文件