日志文件
A 原子性 –undolog实现
C 一致性 –通过其他三个(AID)来实现
I 隔离性 –通过锁实现
D 持久性 –redolog实现
redolog
确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。
当发生数据修改的时候, innodb 引擎会先将记录写到 redo log 中,并更新内存,此时更新就算是完成了,同时 innodb 引擎会在合适的时机将记录操作到磁盘中
redolog 是固定大小的,是循环写的过程.
有了 redolog 之后, innodb 就可以保证即使数据库发生异常重启,之前的记录也不会丢失,叫做 crash safe.
checkpoint之前表示擦除完了的,即可以进行写的,擦除之前会更新到磁盘中,write pos是指写的位置,当write pos和checkpoint相遇的时候表明redo log已经满了,这个时候数据库停止进行数据库更新语句的执行,转而进行redo log日志同步到磁盘中。
redo log 机制图
mysql 通过参数 innodb_flush_log_at_trx_commit 来控制刷盘时机,取值是0、1和2三种值。
0(延迟写): 事务提交时并不会立即将 redo log buffer 中日志写入到 os buffer中,而是每秒写入 os buffer 并调用 fsync() 写入到 redo log file 中。也就是说设置为0时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据
1(实时写,实时刷):事务每次提交都会将 redo log buffer 中的日志写入 os buffer 并调用 fsync() 刷到 redo log file 中。这种方式即使系统崩溃也不会丢失任何数据,是最安全的,同时也是默认值
2(实时写,延迟刷):每次提交都仅写入到 os buffer,然后是每秒调用 fsync() 将 os buffer 中的日志写入到 redo log file
undo log
保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读
Undo Log 是为了实现事务的原子性,在 MySQL 数据库 InnoDB 存储引擎中,还用 Undo Log 来实现多版本并发控制 简称: MVCC)
在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为 Undo Log )。然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK 语句,系统可以利用 Undo Log 中的备份将数据恢复到事务开始之前的状态
注:
undo log 是逻辑日志,可以理解为:
- 当 delete 一条记录时, undo log 中会记录一条对应的 insert 记录
- 当 insert 一条记录时, undo log 中会记录一条对应的 delete 记录
- 当 update 一条记录时,它记录一条对应相反的 update 记录
bin log
用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。
用于数据库的基于时间点的还原。
- binlog是server层的日志,主要做mysql功能层面的事情.
- 与redo日志的区别:
- redolog与undolog是innodb独有的,binlog是所有引擎都可以使用的.
- redolog是物理日志,记录的是在某个数据页上做了什么修改,binlog是逻辑日志,记录的是这个语句的原始逻辑.
- redolog是循环写的,空间会用完,binlog是可以追加写的,不会覆盖之前的日志信息.
数据更新逻辑
- 执行器先从引擎中找到数据,如果在内存中直接返回,如果不在内存中,查询后返回
- 执行器拿到数据之后会先修改数据,然后调用引擎接口重新吸入数据
- 引擎将数据更新到内存,同时写数据到 redo 中,此时处于 prepare 阶段,并通知执行器执行完成,随时可以操作
- 执行器生成这个操作的 binlog
- 执行器调用引擎的事务提交接口,引擎把刚刚写完的 redo 改成 commit 状态,更新完成
redo log 的两阶段提交的理由
先写 redo log 后写 binlog :
假设在 redo log 写完, binlog 还没有写完的时候, MySQL 进程异常重启。由于我们前面说过的, redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行 c 的值是 1 。但是由于 binlog 没写完就 crash 了,这时候 binlog 里面就没有记录这个语句。因此,之后备份日志的时候,存起来的 binlog 里面就没有这条语句。然后你会发现,如果需要用这个 binlog 来恢复临时库的话,由于这个语句的 binlog 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0 ,与原库的值不同。
先写 binlog 后写 redo log:
如果在 binlog 写完之后 crash ,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0 。但是 binlog 里面已经记录了“把 c 从 0 改成 1” 这个日志。所以,在之后用 binlog 来恢复的时候就多了一个事务出来,恢复出来的这一行 c 的值就是 1 ,与原库的值不同。