文章目录
事务特性实现机制
- 事务的隔离性由
锁机制
实现。 - 而事务的原子性、一致性和持久性由事务的
redo日志
和undo日志
来保证。
REDO LOG 称为
重做日志
,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性。因为事务提交后,要把数据写入磁盘,写入一半时宕机的话,如果没有redo日志,则会丢失掉一部分数据,有了redo日志则会记录要修改成什么,重启Mysql后可以借助redo.file去完成未修改成功的部分事务,保证事务的持久性
UNDO LOG 称为
回滚日志
,回滚行记录到某个特定版本,用来保证事务的原子性、一致性。
redo 日志
- 好处
redo日志降低了刷盘频率
redo日志占用的空间非常小
- 特点
redo日志是顺序写入磁盘的
事务执行过程中,redo log不断记录
redo的组成(恢复日志)
- 重做日志的缓冲 (redo log buffer) ,保存在内存中,是易失的。
show variables like '%innodb_log_buffer_size%';
redo log buffer 大小,默认 16M ,最大值是4096M,最小值为1M。
- 重做日志文件 (redo log file) ,保存在硬盘中,是持久的。
redo的整体流程
- 第1步:先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝
- 第2步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值
- 第3步:当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加写的方式
Write-Ahead Log(预先日志持久化):在持久化一个数据页之前,先将内存中相应的日志页持久化。
- 第4步:定期将内存中修改的数据刷新到磁盘中
redo log的刷盘策略
redo log的写入并不是直接写入磁盘的
,InnoDB引擎会在写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
参数,该参数控制 commit提交事务时,如何将 redo log buffer 中的日志刷新到 redo log file 中。它支持三种策略:
注意!该参数影响的是redo log buffer 写入page cache并刷盘到redo.file的执行流程,并不会影响修改写入redo log buffer, 因为这过程是和事务执行同步的
-
设置为0 :表示每次事务提交时不进行刷盘操作。(系统默认master thread每隔1s进行一次重做日志的同步)
-
设置为1 :表示每次事务提交时都将进行同步,刷盘操作( 默认值 )
-
设置为2 :表示每次事务提交时都只把 redo log buffer 内容写入 page cache,不进行同步。由os自己决定什么时候同步到磁盘文件。
redo日志参数设置
innodb_log_group_home_dir
:指定 redo log 文件组所在的路径,默认值为 ./ ,表示在数据库的数据目录下。MySQL的默认数据目录( var/lib/mysql )下默认有两个名为 ib_logfile0 和ib_logfile1 的文件,log buffer中的日志默认情况下就是刷新到这两个磁盘文件中。此redo日志文件位置还可以修改。innodb_log_files_in_group
:指明redo log file的个数,命名方式如:ib_logfile0,iblogfile1…。默认2个,最大100个。innodb_flush_log_at_trx_commit
:控制 redo log 刷新到磁盘的策略,默认为1。innodb_log_file_size
:单个redo log文件设置大小
,默认值为 48M 。最大值为512G,注意最大值指的是整个 redo log 系列文件之和,即(innodb_log_files_in_group 文件个数
*innodb_log_file_size 单文件大小
)不能大于最大值512G。
采用循环使用的方式向redo日志文件组里写数据的话,会导致后写入的redo日志覆盖掉前边写的redo日志。
Undo日志(回滚日志)
redo log是事务持久性的保证
,undo log是事务原子性的保证
。在事务中更新数据的前置操作
其实是要先写入一个 undo log。
Undo日志的作用
- 回滚数据
- MVCC
undo的另一个作用是MVCC,即在InnoDB存储引擎中MVcC的实现是通过undo来完成。当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可以通过undo读取之前的行版本信息,以此实现非锁定读取。
undo的存储结构
InnoDB对undo log
的管理采用段的方式,也就是回滚段(rollback segment)
。每个回滚段记录了1024 个undo log segment
,而在每个undo log segment
段中进行undo页
的申请。
- 每个事务只会使用一个回滚段,一个回滚段在同一时刻可能会服务于多个事务。
- 当一个事务开始的时候,会制定一个回滚段,在事务进行的过程中,当数据被修改时,原始的数据会被复制到回滚段。
- 在回滚段中,事务会不断填充盘区,直到事务结束或所有的空间被用完。如果当前的盘区不够用,事务会在段中请求扩展下一个盘区,如果所有已分配的盘区都被用完,事务会覆盖最初的盘区或者在回滚段允许的情况下扩展新的盘区来使用。
- 回滚段存在于undo表空间中,在数据库中可以存在多个undo表空间,但同一时刻只能使用一个undo表空间。
- 当事务提交时,InnoDB存储引擎会做以下两件事情:
- 将undo log放入列表中,以供之后的purge操作
- 判断undo log所在的页是否可以重用,若可以分配给下个事务使用
undo log的生命周期
假设有2个数值,分别为A=1和B=2,然后将A修改为3,B修改为4
1.start transaction;
2.记录A=1到undo log ;
3.update A = 3;
4.记录A=3到redo log;
5.记录B=2到undo log;
6.update B = 4;
7.记录B =4到redo log;
8.将redo log刷新到磁盘
9.commit
流程图
事务提交之前,就会先把undo log buffer里的数据刷新到磁盘的undo log tablespace里。而且是在刷新redo log之前,就要先写undo log了