Redo log是事务持久性的保证,Undo log是事务原子性的保证。在事务中更新数据的前置操作其实就是要写入Undo log。
事务需要保证原子性,也就是事务中的操作要么全部完成,要么什么也不做。但有时候事务执行到一半会出现一些情况,比如:
以上情况出现,我们需要把数据改回原先的样子,这个过程称之为回滚,这样就可以造成一个假象:这个事务看起来什么都没做,所以符合原子性要求每当我们要对一条记录做改动时(这里的改动可以指INSERT、DELETE、UPDATE),都需要“留一手”一一把回滚时所需的东西记下来比如:
MySQL把这些为了回滚而记录的这些内容称之为撤销日志或者回滚日志(即undo log)。注意,由于查询操作(SELECT)并不会修改任何用户记录,所以在查询操作执行时,并不需要记录相应的undo日志。此外,undo log会产生redo log,也就是undo log的产生会伴随着redo log的产生,这是因为undo log也需要持久性的保护。
作用一:回滚数据
用户对undo日志可能有误解:undo用于将数据库物理地恢复到执行语句或事务之前的样子。但事实并非如此。undo是逻辑日志,因此只是将数据库逻辑地恢复到原来的样子。所有修改都被逻辑地取消了,但是数据结构和页本身在回滚之后可能大不相同。
这是因为在多用户并发系统中,可能会有数十、数百甚至数千个并发事务。数据库的主要任务就是协调对数据记录的并发访问。比如,一个事务在修改当前一个页中某几条记录,同时还有别的事务在对同一个页中另几条记录进行修改。因此,不能将一个页回滚到事务开始的样子,因为这样会影响其他事务正在进行的工作。
作用二:MVCC(多版本并发控制)
undo的另一个作用是MVCC,即在InnoDB存储引擎中MVCC的实现是通过undo来完成。当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可以通过undo读取之前的行版本信息,以此实现非锁定读取。
InnoDB对undo log管理采用段的方式,也就是回滚段(Rollback Segment)
。每个回滚段记录了1024个undo log segment
,而在每个undo log segment
段中进行undo页的申请。
rollback segment
,因此支持同时在线的事务限制为1024。虽然对绝大多数的应用来说都已经够用。rollback segment
,故其支持同时在线的事务限制提高到了128*1024show variables like '%innodb_undo_logs%';
虽然InnoDB1.1版本支持了128个rollback segment
,但是这些rollback segment
都存储于共享表空间ibdata中。从InnoDB1.2版本开始,可通过参数对rollback segment
做进一步的设置。这些参数包括:
undo log 相关参数一般很少改动。
show variables like '%innodb_undo_tablespaces%';
在更新Buffer Pool中的数据之前,我们需要先将该数据事务开始之前的状态写入Undo Log中。假设更新到一般出错了,我们就可以通过Undo Log来回滚到事务开始之前。
以上面的例子来说,假设执行rollback,那么对应的流程应该是这样:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。