事务简介
事务是数据库区别于文件系统的最重要特征之一。事务可以保证数据库从一个状态转移到另一个状态,也就是说在一个事务中的语句要么全部一起提交(所有修改都会保存),要么回滚(所有修改都不会保存)。
事务的性质:原子性,一致性,隔离性,持久性(ACID)保证一个事务的正确执行。每种性质具体含义具体参考:https://blog.csdn.net/puliao4167/article/details/89043612
事务的分类
事务可以分为扁平事务,带有保存点的扁平事务,链事务,嵌套事务,分布式事务
- 扁平事务,是平常用的最多的事务,所有的操作处于同一个层次,由begin开始,由commit或者rollback结束,其间的操作语句都是原子性的,要么都执行,要么都不执行。
- 带有保存点的扁平事务,除了支持扁平的事务外,还允许在回滚的时候,可以回滚到同一事物的较早的状态,保存点是用来提醒系统记住当前的状态。如果没有特殊的(显式的)保存点,在回滚的时候默认会回滚到事务起始处,
- 链事务,可以视为保存点模式的另一种方式,带有保存点的扁平事务中的保存点是易失的,而非持久的,当系统发生崩溃时,保存点即会消失,事务要从头开始执行。链事务的思想是:在提交一个事务的时候,释放不需要的数据,将要处理的上下文隐式的传递给下一个开启的事务(形成一个链状)
- 嵌套事务是一个层次结构框架,一个顶级事务中调用子事务
- 分布式事务是在分布式的环境下运行的扁平事务
redo日志
首要要清楚,事务ACID中的隔离性是由锁机制来实现的,而另外的三个性质原子性,持久性,一致性由redo日志,undo日志保证。
redo log(重做日志)是有两个部分组成:一个是在内存中的重做日志缓冲,另一个是在磁盘中的重做日志文件。在InnoDB存储引擎中,大部分情况下 Redo是物理日志,记录的是数据页的物理变化。Redo log的主要作用是用于数据库的崩溃恢复。redo的流程如下:
- 先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝
- 生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值
- 当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加写(顺序写)的方式
- 定期将内存中修改的数据刷新到磁盘中
从上图中可以看出,Innodb其通过Force Log at Commit 机制实现事务的持久性,即当事务提交时,先将 redo log buffer 写入到 redo log file 进行持久化,待事务的commit操作完成时才算完成。这种做法也被称为 Write-Ahead Log(预先日志持久化),在持久化一个数据页之前,先将内存中相应的日志页持久化。
Force Log at Commit机制就是靠InnoDB存储引擎提供的参数 innodb_flush_log_at_trx_commit
来控制的,该参数可以控制 redo log刷新到磁盘的策略,设置该参数值也可以允许用户设置非持久性的情况发生,具体如下:
- 当设置参数为1时,(默认为1),表示事务提交时必须调用一次
fsync
操作,最安全的配置,保障持久性 - 当设置参数为2时,则在事务提交时只做write操作,只保证将redo log buffer写到系统的页面缓存中,不进行fsync操作,因此如果MySQL数据库宕机时 不会丢失事务,但操作系统宕机则可能丢失事务
- 当设置参数为0时,表示事务提交时不进行写入redo log操作,这个操作仅在master thread 中完成,而在master thread中每1秒进行一次重做日志的fsync操作,因此实例 crash 最多丢失1秒钟内的事务。(master thread是负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性)
undo日志
undo log主要记录的是数据的逻辑变化,为了在发生错误时回滚之前的操作,需要将之前的操作都记录下来,然后在发生错误时才可以回滚。redo log存放在内存的重做日志文件中,undo 存放在数据库中一个特殊的段中(undo 段),是一种逻辑日志。undo有两个作用,一是记录操作用于事务回滚,第二是MVCC。在回滚的时候,它实际上是做的相反的工作,比如一条INSERT ,对应一条 DELETE,对于每个UPDATE,对应一条相反的 UPDATE,将修改前的行放回去,所以其要在DML语句修改之前记录数据。
当进行insert或者update修改聚簇索引前,要记录undo日志,需要注意的是,记录undo日志,同时也要记录redo日志。以下一个例子
假设有A、B两个数据,值分别为1,2.
1. 事务开始
2. 记录A=1到undo log
3. 修改A=3
4. 记录A=3到 redo log
5. 记录B=2到 undo log
6. 修改B=4
7. 记录B=4到redo log
8. 将redo log写入磁盘
9. 事务提交
参考《高性能mysql》、《MYSQL技术内幕 Innodb存储引擎》
浅谈mysql事务中的redo和undo https://www.jianshu.com/p/20e10ed721d0