在DB2中,该机制使用日志功能实现。所谓日志,可以被认为在一条事务被落实之前,能够保证其记录被写入永久存储系统的一种方法。
那么为什么需要日志呢?直接把变化的数据写入磁盘不是更好?之所以需要日志,主要是从性能考虑。通常情况下,每一个事务包含若干条数据更改语句,每个更改可能需要操作大量的数据。如果将这些数据直接写入磁盘才返回给应用端,那么将严重影响写的性能,因此,DB2采用写日志优先算法,即先写日志,再写数据,而写数据的过程使异步的。
如图所示日志原理,当插入\更改\删除数据时,该条记录并不会直接写到数据盘,而是首先写到日志文件。而缓存池数据什么时候写到数据盘,是个异步过程。这样即使某一时刻突然宕机,数据没有从缓存池内存写到数据盘也没有关系,因为数据已经记到日志文件里了。当重新开机进行恢复的时候,DB2将日志文件的内容重写到数据盘,保证数据库的一致性
DB2的日志理解难点
在DB2中最早的recovery时间点,是由minBuffLsn 和 lowTranLsn 的最小值决定的。
minBuffLsn: represents the oldest change to a page in the buffer pool that has not been written and persisted to disk yet.
lowTranLsn: represents the oldest active uncommitted transaction (specifically the LSN of the first log record it wrote).
在DB2和ORACLE数据库都还有一个约定,从buffer pool中写数据到磁盘之前其对应的redo log必须先从log buffer pool中写到磁盘中。
注意:这里的log buffer pool中的redo log没有要求是已经committed的。
所以,在数据库中,还没有被提交的数据被写到磁盘中是很正常的事情,只要这块数据所对应的redo log已经被写入到磁盘中,对于这个交易是否已经提交,不关紧要。
那么在recovery的时候就会出现这样的情况:
minBuffLsn < lowTranLsn : 有已经提交的交易(commit动作会触发数据库将对应的redo log写入到磁盘)数据还有没有被从buffer pool中写入到磁盘,所以recovery时从minBuffLsn对应的log开始,redo后面那些已经提交的或者未提交的交易,重建transaction table。
lowTranLsn > minBuffLsn : 有还没有提交的交易(但是redo log是已经写入到磁盘中的)的数据已经被写入到磁盘中,所以recovery时将从lowTranLsn对应的log开始,这部分数据已经被写入到磁盘中的redo log只是读取一下,创建transaction table。