MySQL学习:事务日志

事务的隔离性是通过锁实现,而事务的原子性、一致性和持久性则是通过事务日志实现。说到事务日志,不得不说的就是redo和undo。

在存储引擎修改表的数据时,会将数据从磁盘拷贝到内存中,然后修改内存中的数据拷贝,再将修改行为持久化到磁盘中,而不用每次将修改的数据本身持久化到硬盘中

1.redo log(重做日志)

在innoDB的存储引擎中,事务日志通过重做(redo log)日志和日志缓冲(redo Log Buffer)实现。事务开启时,事务中的操作,都会先写入存储引擎的日志缓冲中,

每次事务日志的写入并不会直接写入到文件中,而是会写入到缓冲区中,在一定事件的触发下,才会将缓冲区内的数据写入到日志文件中,这就是常说的“日志先行”(Write-Ahead Logging)。当事务提交之后,在Buffer Pool中映射的数据文件才会慢慢刷新到磁盘。

当事务日志持久化以后,就会将脏数据慢慢写回磁盘中,目前大多数存储引擎都是这么做的,这也被叫做预写式日志(Write-Ahead Logging),所以修改数据的时候需要进行两次写磁盘的操作。

如果数据库崩溃或者宕机,那么当系统重启进行恢复时,就可以根据redo log中记录的日志,把数据库恢复到崩溃前的一个状态。未完成的事务,可以继续提交,也可以选择回滚,这基于恢复的策略而定。

​ 在系统启动的时候,就已经为redo log分配了一块连续的存储空间,以顺序追加的方式记录Redo Log,通过顺序IO来改善性能。所有的事务共享redo log的存储空间,它们的Redo Log按语句的执行顺序,依次交替的记录在一起。如下一个简单示例:

​ 记录1:<trx1, insert…>

​ 记录2:<trx2, delete…>

​ 记录3:<trx3, update…>

​ 记录4:<trx1, update…>

扫描二维码关注公众号,回复: 12662494 查看本文章

​ 记录5:<trx3, insert…>

2.undo log(回滚日志)

​ undo log主要为事务的回滚服务。在事务执行的过程中,除了记录redo log,还会记录一定量的undo log。undo log记录了数据在每个操作前的状态,如果事务执行过程中需要回滚,就可以根据undo log进行回滚操作。单个事务的回滚,只会回滚当前事务做的操作,并不会影响到其他的事务做的操作。

补充:

​ 即使事务已经被提交了,undo log也不会被立刻删除,因为需要保证日后事务也可以进行回滚操作。当事务隔离级别为REAPEATABLE READ(可重复读,即MySQL默认的事务隔离级别)时,事务读取的都是开启事务时的最新提交行版本,只要事务不结束,该行版本就不能删除,即undo log也不能被删除。

​ 以下是undo+redo事务的简化过程

​ 假设有2个数值,分别为A和B,值为1,2

  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;

  1. 将redo log刷新到磁盘

  2. commit

​ 在1-8的任意一步系统宕机,事务未提交,该事务就不会对磁盘上的数据做任何影响。如果在8-9之间宕机,恢复之后可以选择回滚,也可以选择继续完成事务提交,因为此时redo log已经持久化。若在9之后系统宕机,内存映射中变更的数据还来不及刷回磁盘,那么系统恢复之后,可以根据redo log把数据刷回磁盘。

image-20201128211829649

​ 总结一下,undo log是用来在事务失败后进行回滚(roll back),保证了事务的原子性

redo是用来恢复未写入data file里的已成功事务更新的数据,保证了事务的持久性和一致性

二者缺一不可,如果只有redo,就不能在事务提交前刷新脏数据,这样一旦处理大事务,内存的占用会高的让你无法想象;而只有undo的话,就必须要在事务提交前刷脏完成,否则一旦宕机,某些数据就会直接消失,破坏了持久性。(脏数据:因为进行的修改并不会立刻持久化到硬盘空间中,就会造成有一段时间data file和redo log中的数据不一致,这就是脏数据)

猜你喜欢

转载自blog.csdn.net/weixin_44777669/article/details/110293623