前言

        关于mysql的InnoDB存储引擎的关键知识点,已经输出了6篇文章了,但是好像阅读量并不大,可能大家都不太喜欢理论性特别强的东西?或者是这些知识点难度有点高,不太容易被接受?不过,我觉得我分享这些东西都是mysql的核心知识,相当重要,难道是有难度?当然,我已经尽可通用较为通俗的表述来分享它。写作功能有限,如果你有好的建议,就在评论区告诉我吧。

1. 什么是事务

        事务可以把数据库从一种一致性的状态转换为另一种一致状态。通俗一点,一个数据库操作任务,包含多个子任务,子任务里有查询,有修改,有删除,那么这个操作任务在执行过程中,所有的子任务要么一起成功,要么一起失败并回滚到操作任务开始前的状态。

2. 事务的特性

        事务有ACID四个特性,分别是:

        原子性(Atomicity):事务原子性的关键在于不可分割,即一个事务任务的所有子任务要么一起成功要么一起回滚。

        一致性(Consistency):事务一致性重点是指事务操作前后的状态变化,即前后的状态必须是一致,具体的表现就是同一事务任务内的所有子任务要么一起成功要么一起失败回滚。

        隔离性(Isolation):事务隔离性的关注点是在多个事务之间的相互影响,即多个事务任务之间是互斥和隔离的,彼此之间不能相互影响。

        持久性(Durability):事务持久性的关注点在于事务操作的结果,即事务操作成功后,结果是永久性的,不存在说停电了服务再重启后结果又变了。

        事务的四大特性,实际是从不同的角度对于事务定了一些标准,InnoDB引擎的事务也符合这些特性的,但实际是有的数据库的事务有可能只符合了其中几个特性。

3. 事务的隔离级别

        SQL标准化组织定义了四种事务隔离级别,InnoDB默认的事务隔离级别是可重复读。

        read uncommitted 读未提交

        read committted 读已提交

        repeatable read 可重复读

        serializable 序列化

        事务有四大特性,就是原子性、一致性、隔离性、持久性,其中的隔离性是通过锁来实现,而原子性、一致性、持久性是通过数据库的redo log 和undo log实现的。那么redo log和undo log实现的,这两个是什么玩意?下面分别具体说一下。

4. redo log

        redo log叫做重做日志,用来保证事务的原子性和持久性的重要机制,当mysql服务器意外崩溃或宕机时,可以保证已提交的事务持久化到磁盘。那么redo log是怎么保证事务提交后发生意外时数据会持久化到磁盘中呢?

        对于mysql的InnoDB存储引擎,在开启事务后,执行一个事务操作,如增、删、改时,不会直接去磁盘上找到要操作的数据,然后直接修改,而是会先查看一下缓存池(buffer pool),看看要操作的数据是否在缓冲池中,如果不在缓存池中,则直接从磁盘上把包含要操作数据行所在页加载到缓存池中,再对缓存池中的数据进行修改,接着会把操作后的数据写入到重做日志缓冲池中(redo log buffer),事务提交时,重做日志缓冲池中操作后的数据会写入到重做日志文件中。

        等等,是不是哪里不对,事务操作(增、删、改)数据只对缓存中的数据进行修改,不写入磁盘吗?这里要注意的是,mysql InnoDB的设计不是直接把事务操作后的数据直接写入到磁盘中,《mysql InnooDb存储引擎的体系结构和逻辑存储结构》中已说过页是InnoDB存储引擎磁盘管理的最小单位,如果立刻要写入磁盘的话,尽管事务操作了个别行的数据,那也需要更新整个数据页,这样就过于浪费数据库性能了。那为什么又写入重做日志了,难道这就不浪费数据库性能了?

        当然不会,因为从重做日志缓冲中写入到重做日志文件中的数据,只是一条日志,日志的内容就是操作是哪个页的数据,第几行(偏移量),操作后的数据是什么样,而不是整个数据页,权衡一下,更新一个页和更新一行数据,当然一行所消耗的代价更小。这么说好像也能理解了,那么事务操作数据后,不写入磁盘,难道不怕数据丢了吗?这个不用担心,事务提交时,不是写入重做日志了嘛,如果真发生故障了,可以根据故障时间和重做日志进行数据恢复,由于redo log是顺序写入的,再顺序读出恢复也很快的。正常情况下,缓存池中事务操作后的数据会有另外一套机制从缓存池刷新到磁盘上的。

        这里还要再多说一点,从重做日志缓存池写入到重做日志文件文件还有点套路,有一个参数innodb_flush_log_at_trx_commit控制写入日志文件的策略,默认值为1,表示事务提交成功时,肯定会先从重做日志缓存池写入操作系统缓存,再通过fsync操作从系统缓存写入磁盘。另外两个值是0和2,0表示每隔1秒才会执行fsync操作,如果故障就发生在这一秒内,那数据就丢一部分;2表示仅写入到系统缓存,不会执行fsync操作,这种情况就要祈祷发生的故障是数据库服务,而不是操作系统,否则也会丢失未从系统缓存中刷新到重做日志的那部分数据。

mysql InnoDB 事务的实现原理-LMLPHP

        是不是感觉这里面套路很多,其实这些还好,仔细梳理一下,还能理解清楚,mysql的优化器设计才是真复杂呢。

5.undo log

        undo log的作用就是用于事务操作失败时回滚数据,保证事务的一致性的。举个例子,如果InnoDB执行了一个insert操作,那么undo log会记录一条delete操作,如果是InnoDB执行了一个delete操作,那么undo log会记录一条insert操作;如果InnoDB执行了一个update操作,那么undo log会记录一条相反的update操作,将修改前的数据改回去。另外一个作用就MVCC(多版本并发控制),即当用户读取一行数据的时候,若该行记录被其他事务锁定,就会通过undo log读取之前版本的数据,实现非锁定读取。

6.总结

  1. redo log记录的是物理日志,是修改后的物理数据和一些其他信息,平时不会去读取,遇到意外故障时可以保证数据的持久化。
  2. undo log也可以理解为一种重做日志,不过和redo log不一样,undo log记录的是逻辑日志,即用于数据修改的物理操作语句(sql)。
  3. undo log会产生redo log,因为回滚操作时,也可能会发生停电之类的意外,也需要持久性的安全保护。

 

11-29 11:18