数据库之事务的实现

事务

谈及数据库,就不得不提到数据库的四大特性:原子性、一致性、隔离性、持久性。这里主要谈谈持久性。
相较于文件系统,数据库系统的不同之处在于它存在事务。在文件系统中,如果正在写文件时,操作系统突然崩溃了,那么文件就会丢失。但是在数据库中,因为事务的存在,在数据库保存时,要么所有的修改都保存,要么所有的修改都不保存。事务将数据库从一种一致性状态转换到另一种一致性状态。

事务的基本概念

事务是访问数据库并更新数据库中数据的一个数据单元。一个事务中可能包含多行语句,一个事务中的语句要么都执行成功,要么都不执行。
事务的隔离级别有四种,:读未提交、读已提交、可重复读、串行化
MySQL默认的隔离级别是可重复读,Oracle默认的隔离级别是读已提交。

事务的实现

事务的原子性、一致性、持久性由redo log(重做日志)和undo log来实现。redo log和undo log的不同点在于:

  • redo log可以恢复事务提交的页操作,因此用来保证事务的原子性和持久性,而undo log可以归滚到某个特定的版本,因此用来保证事务的一致性。
  • 两者记录日志的方式也不同,redo log记录的是物理日志,物理日志是页的物理修改操作。undo log记录的是逻辑日志,根据行数据进行记录。
  • redo log基本上是顺序读写(顺序读写比随机读写快),数据库运行时不需要对redo log进行读取,而undo log是需要随机读写的。

redo log(重做日志)

重做日志是由重做日志缓存(存在于内存中,是易失的)和重做日志文件(存在于磁盘中,是持久的)组成的。

当事务提交时,必须先将事务的日志写入重做日志进行持久化,等到事务Commit以后才算完成。这就是Force log at Commit机制,这个机制保证了事务的持久性。

当事务提交时,需要先将重做日志缓存写到重做日志中,然后调用一次fsync操作。这是因为重做日志文件开始时没有使用O_DIRECT选项,实际上重做日志写入了文件系统缓存而没有写入磁盘。fsync操作会确保日志被写入磁盘。

基本概念:Linux中设置了缓冲区,数据的写入一般先写入缓冲区,然后再写入磁盘。
fsync系统调用:传入参数filedes后,fsync只对filedes指定的文件起作用,fsync在数据写磁盘操作结束后才会返回,这确保了数据能够安全的写入磁盘。
O_DIRECT:在Linux内核中,写入一个文件需要经过Cache Page,但如果用O_DIRECT打开文件,就可以直接面对磁盘进行IO.

由于fsync的效率取决于磁盘,因此磁盘的性能决定了事务提交的性能,也就是数据库的性能。

InnoDB引擎中,可以设置参数innodb_flush_log_at_trx_commit来控制重做日志刷新到磁盘的策略。

  • 参数的默认值为1,表示事务提交时必须调用一次fsync操作。
  • 参数的值为0,表示提交事务时不进行写入重写日志的操作,实际上这个操作在master thread中完成,每1秒会调用一次fsync操作。
  • 参数的值为2,表示事务提交时将重做日志写入重做日志文件按,但仅写入文件系统的缓存中,不进行fsync操作。在此设置下,如果是数据库发生宕机,并不会导致事务丢失,但如果是操作系统宕机,会失去存在缓存中还没有来得及写入磁盘的那部分数据。

注意:虽然设置innodb_flush_log_at_trx_commit为0或2可以提高事务提交的效率,但是这种设置方式丧失了ACID特性,可能会导致事务日志的丢失。


undo log

undo log主要用作事务的回滚。在对数据库进行修改时,InnoDB不仅会产生redo log,也会产生undo log。如果用户执行的事务失败了或者用户用ROLLBACK语句回滚,就可以利用undo log回滚到之前的样子。

redo存放在重做日志文件中,存放在数据库内部的一个特殊字段(segment)中,这个段称为undo段(undo segment)。

undo log的作用有两个:一是对事务进行回滚,二是MVCC.

由于undo log是逻辑日志,因此undo并非是将数据库物理的恢复到之前的样子,而是将数据库逻辑的恢复到原来的样子。具体的表现是,当用户插入一万条记录会让表空间增大。当用户执行ROLLBACK时,会将事务进行回滚,但是表空间的不会变小。因此,InnoDB的回滚实际上是做与之前相反的操作。

InnoDB引擎中MVCC的实现是通过undo来完成的。当用户需要读取一行记录时,如果该记录已经被其他事务占用,当前事务可以通过undo读取之前的行版本信息,实现非锁定读取。

另外,MySQL数据库还有一种二进制日志(binlog),它用来进行POINT-IN-TIME(PIT)的恢复及主从复制(Replication)环境的建立。表面上看,它和重做日志十分相似,但其实两者大有不同。

  • 重做日志是在InnoDB存储引擎层产生的,而二进制日志是在MySQL数据库的上层产生的,MySQL数据库中的任何存储引擎对于数据库的更改都会产生二进制文件。
  • 两者日志记录的内容形式不同。二进制日志是一种逻辑日志,记录的是对应的SQL语句,而重做日志是物理日志,记录的是对于每个页的修改。
  • 两者日志记录写入磁盘的时间点不同。二进制日志只在事务提交完成后进行一次写入,重做日志并不是随着事务提交的顺序进行写入的,而是在事务进行中不断的被写入。

重做日志是在事务执行的同时并发写入的,所以在文件中记录的顺序并不是事务开始的顺序。由于记录的是物理日志,每个事务会对应多个日志条目。而二进制日志每个事务仅对应一个日志。

总结

重做日志

  1. 重做日志包含redo log和undo log
  2. redo log保证了事务的持久性,undo log保证了事务的一致性。
  3. redo log记录物理日志(对页的修改,具体表现为数据的变化),undo log记录逻辑日志(具体表现为sql语句)。
  4. 重做日志由重做日志缓存和重做日志文件组成。
  5. Force log at Commit:在事务提交时,必须将事务日志写到重做日志中进行持久化,并Commit后才算完成。
  6. fsync调用(innodb_flush_log_at_trx_commit参数值为0、1、2时分别采取什么策略)
  7. undo log的作用
  8. binlog的作用以及与重做日志的差异
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值