数据库事务的四大特性---持久性(redo log)
今日份鸡汤:时间的长河总是以它的速度一直往前走,人生的一秒一秒都在成为过往。要勇敢地生活,坦然去面对所有的变化~
定义:
只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。
实现原理:
基于redo log,mysql的数据是存在磁盘当中的,但是如果每次去读数据都需要经过磁盘io,那么效率就很低,所以innodb提供了一个缓存buffer,这个buffer中包含了磁盘中部分数据页的一个映射,作为访问数据库的一个缓冲,当从数据库读取这个数据,就会先从buffer中取,如果buffer中没有,就从磁盘中取,读取完之后就放到buffer缓存中,那么当向数据库写入数据的时候,也会首先向这个buffer中写入数据,然后定期将buffer中的数据刷入到磁盘上,进行持久化的操作,那么这个时候就存在一个问题,虽然读写效率提升了,但是他也增加了数据丢失的风险,如果buffer中的数据还没有来得及同步到这个磁盘上,这个时候mysql宕机了,那么buffer中的数据就会丢失,进而造成这个数据的丢失,数据丢失了,事务的持久性就没有办法保证,就是因为这个背景,redo log就被引进来了,那么改进之后的流程是这样的:当数据库中的数据要进行新增或修改的时候,除了修改buffer中的数据,还要把这次的操作记录到redo log中,如果mysql宕机了,还有redo log去恢复数据,redo log是预写式日志,预写式日志是什么意思呢?也就是说他会将所有的修改先写入到日志里面,然后再更新到buffer里面,也就保证了这个数据不会丢失,那么这样他就保证了持久性,既然redo log也需要把这个事务提交的日志写入到磁盘,那他为什么比直接将buffer中的数据写入到磁盘中要快呢?主要有两个原因,一个是buffer中的数据持久化是随机写的io,每次修改的数据位置都是随机的,但是redo log 是追加模式的,他是在文件的尾部去追加,属于一种顺序io的操作,这种方式就很快,kafka也是采用这种顺序io机制去操作的。第二个就是buffer持久化数据是以这个数据页,page为单位的,mysql数据页大小默认为16kb,一个数据页上一个小小的修改,都要把整个页的数据写入,那么redo log 只需要写入真正的部分就可以了,这种无效的io就大大减少了,所以redo log 要比buffer快的很多,redo log 是什么时候同步到磁盘呢?Redo log没有同步之前是在redo log缓冲区中,那么这个时候,就算是宕机了也没有关系,首先事务没有执行完,还没有提交,那么我们恢复好数据库之后还可以走回滚的操作,可以通过undo log去做回滚。
持久化有如下三种方式,我们使用2就可以了:
(1)表示当提交事务时,并不将缓存区的redo日志写入磁盘的日志文件,而是等待主线程每秒刷新。
(2)在事务提交时,将缓冲区的redo日志同步写入到磁盘,保证一定会写入成功。
(3)在事务提交时,将缓冲区的redo日志异步写入到磁盘,即不能完全保证commit时肯定会写入redo日志文件,只是有这个动作。