在标题三中,我们认为InnoDB不符合预写日志机制,这是基于事务提交的标志设置是在刷出日志之前完成的,这一点,是基于InnoDB的代码实现的意图来下的结论。InnoDB认为在内存的状态设置了提交标志就算是“事务提交”完成了。
但是,传统的数据库理论认为,“事务提交”需要符合持久性(ACID之D),也就是说,事务的最后一个记录输出到稳定存储介质后,才能算作是“事务提交”完成了,因为只有这样,事务才不至于因数据库系统崩溃而发生不一致(设置内存提交标志后、刷出日志前,数据库系统可能崩溃)。从这个意义上讲,InnoDB符合预写日志机制。
五 当上述问题发生时,InnoDB怎么避免数据不一致的问题?
InnoDB设置内存提交标志后、刷出日志前,数据库系统可能崩溃。这种状态下:
q InnoDB设置内存提交标志后:事务的数据已经被其他事务可见,存在误导其他事务发生数据不一致的可能性。
q 正常情况下,日志被刷出:这时,刷出的标志是以本事务的LSN为刷出的位置标志,调用log_write_up_to(lsn, flush)函数完成,其中的参数lsn就是本事务的在日志中的最后位置,所以一旦刷出执行成功,则一个事务的全部信息就被完整地刷出了。此后系统崩溃,数据库引擎做恢复时事务的完整信息存在,则事务被恢复,能够保证数据的一致性。这就是ACID中的D特性对A特性的关联保障之处。
q 刷出日志前,数据库系统崩溃:这时,事务发生数据不一致的可能性就一定发生。数据库引擎做恢复时事务的完整信息不存在,则事务被回滚,而其他读过本事务内存态提交过的数据的事务应LSN值必须大于本事务的LSN值,所以因事务信息不完整也会被回滚,所以崩溃的情况下也能保证数据的一致性。
六 InnoDB先提交事务后刷出日志的方式有什么好处?
q 首先,刷出日志需要花费较多的时间,这样会阻塞事务的提交,导致数据库引擎整体的事务吞吐量下降。
q 其次,事务提交提前与刷出日志正好解决了上述的问题,能够有效提高事务吞吐量。