MySql 保证事务的原子性和持久性

1、前言

为了实现事务的原子性和持久性,mysql引入了undoredo日志(即undo logredo log)。本篇博客来讲解下undo和redo的概念,以及mysql如何利用undo和redo进行异常宕机恢复。

2、undo日志

2.1 作用

undo日志记录的是修改前的值

2.2 举例

事务A要将字段age的值由原来的1修改为2,要将name的值由原来的Alice修改为Bob,undo日志记录的过程表如下:
在这里插入图片描述
假设现在数据库出现了宕机的问题,分为两种情况:

  • 如果在上表第三步之前数据库挂了,则最终数据和日志均为原数据;
  • 如果第三步及以后出现异常,则undo已经记录了原来的值,则可以利用undo日志将数据恢复为原数据。

2.3 原理

当事务提交之后,undo不会被马上删除,而是放入待删除队列,由purge线程来判断是否删除和处理。

在mysql5.6之前,undo只存在于共享表空间中,之后的版本中,则可以配置为独立的文件。

undo内部默认128个回滚段槽(rseg slot),每个rseg slot内部有1024个回滚段(rollback segment)。其中:

  • slot0——共1个,预留给系统表空间

  • slot1~slot31——共31个,预留给临时表空间

  • slot32~slot127——共96个,预留给undo独立表空间

由于undo日志会被清理掉,不能保证事务的持久性,因此才需要引入redo日志来保证事务的持久性。

3、redo日志

3.1 作用

redo日志记录的是修改后最新的数据和冗余的undo日志

3.2 举例

事务B要将字段age的值由原来的1修改为2,要将name的值由原来的Alice修改为Bob,redo日志记录的过程表如下:
在这里插入图片描述
其中,redo日志必须先于数据写入磁盘(即步骤8和步骤9的顺序不能改变)。因为如果不这样,在数据提交之后再写redo日志,一旦redo日志的写入过程出现异常,将无法保证持久性。

记录redo日志时,先记入redo log buffer,最后再一起写入磁盘,这样可以减少IO,提升性能。

另外,未提交的事务回滚了的事务也会计入redo日志。

现在假设:如果上面事务B回滚(当做新的事务C),则redo记录的过程表如下:
在这里插入图片描述

3.3 原理

mysql的恢复策略是:

  1. 恢复时,先根据redo重做所有事务(包括未提交和回滚了的)
  2. 再根据undo回滚未提交的事务。

如上,如果事务B异常未提交事务就宕机,恢复时,先根据redo日志将数据恢复为age=2&name=Bob,然后再根据undo记录的age=1&name=Alice将数据恢复如初。

如果事务C异常未提交事务就宕机,恢复时,根据redo日志,可以直接恢复至age=1&name=Alice的初始状态。

redo日志会随着时间推移而越来越大,为了提升redo的恢复性能,引入了checkpoint机制,在恢复的时候,只需要从checkpoint的位置往后恢复即可。

发布了5 篇原创文章 · 获赞 0 · 访问量 397

猜你喜欢

转载自blog.csdn.net/weixin_32822759/article/details/105505096