InnoDB事务

1.前言

事务是数据库区别于文件系统的重要特性之一,InnoDB存储引擎中的事务符合ACID的特性,即

  • 原子性(atomicity)
  • 一致性(consistency)
  • 隔离性(isolation)
  • 持久性(durability)

本文参考了姜承尧先生的《MySQL技术内幕InnoDB存储引擎》一书

2.事务四大特性

A(Atomicity)原子性:指整个数据库事务是不可分割的工作单位。只有使事务中的所有操作都执行成功了才能算整个事务执行成功,过程中只要有一个操作失败,就要回滚事务。

C(Consistency)一致性:指事务将数据库从一种状态转变为下一种一致的状态。在事务开始前和事务结束后,数据库的完整性约束没有被破坏。例如,一个列为id的字段,要求不能有重复id,但是事务结束后,出现了相同id,这就破坏了一致性

I(Isolation)隔离性:隔离性还有其他称呼,如并发控制、可串行化、锁等等。当事务A操作对象A时,其他事务不能操作A(隐身)。

D(Durability)持久性:一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便在数据库系统遇到故障的情况下也不会丢失事物的操作。

 

其中隔离性会产生的几种问题:

1、脏读 

2、不可重复读

3、幻读

4、丢失更新
(这几个的概念在上一篇InnoDB锁中已经解释过了)

3.事务的分类

  • 扁平事务
  • 带有保存点的扁平事务
  • 链事务
  • 嵌套事务
  • 分布式事务

3.1 扁平事务

扁平事务是事务类型最简单的一种,在扁平事务中,所有操作都处于同一层次,由BEGIN WORK 开始,由COMMIT WORK 或者ROLLBACK WORK 结束,期间操作是原子性的,要么都完成要么都回滚。

3.2 带有保存点的扁平事务

有时候全部操作回滚的代价比较高,例如买三张转机飞机票去北极,前两张都买好了,等买第三张的时候,机场告诉你票都抢没了,你需要买第二天的票,这时候回滚全部飞机票代价比较大,所以就需要一个带节点的扁平事务,只需回滚到第二张飞机票即可。

概念:允许事务执行过程中回滚到同一事务中较早的一个状态。保存点(Savepoint)用来通知系统保存当前事务状态,以便之后发生错误回滚到当前节点。

3.3 链事务

带有保存点的扁平事务是易失的,当发送系统崩溃的时候所以保存点消失。

链事务思想:在提交事务时,释放不需要的数据对象,将必要的处理上下文隐式地传给下一个要开始的事务。提交事务操作和开始下一事务操作将合并为一个原子操作,意味着下一个事务将看到上个事务的执行结果。链事务与带有保存点的事务不同的是, 带有保存点的扁平事务能回滚到任意正确的保存点, 而链事务中的回滚仅限于当前事务. 另外, 链事务在执行了COMMIT后即释放了当前事务所持有的锁, 而带有保存点的扁平事务不影响迄今为止所持有的锁

3.4 嵌套事务

嵌套事务是一个层次结构框架,由一个顶层事务控制着各个层次的事务,子事务既可以提交也可以回滚,但是它的提交不会立马生效,需要顶层事务也提交,任意事务的回滚都会引起子事务的回滚。

3.5 分布式事务

通常是一个在分布式环境下运行的扁平事务。

4.事务的实现

事务隔离性由锁实现,原子性、一致性、持久性通过数据库的redo log 和 undo log 来完成。redo log称为重做日志,用来保证事务的原子性和持久性。undo log 用来保证事务的一致性。redo 和 undo 都视为一种恢复操作,redo 恢复提交事务修改的页操作,而undo回滚行记录到某个特定版本。redo 是时物理日志,记录的时页的物理修改操作,undo 是逻辑日志,记录每行。

4.1 redo

  • 4.1.2 概述

重做日志用来实现事务的持久性。

组成:

  • 内存中的重做日志缓冲(redo log buffer),是易失的。
  • 重做日志文件(redo log file),是持久的。

InnoDB 是事务的存储引擎,其通过Force Log at Commit 机制实现事务的持久性,当事务提交时,必须先将该事务的所有日志写到重做日志文件进行持久化,待事务的提交操作完成才算完成。

redo log 用来保证事务的持久性,undo log 用来帮助事务回滚及MVCC的实现。

为了保证每次日志都写入重做日志文件, 在每次将重做日志缓冲写入日志文件后, InnoDB都需要调用一次fsync操作. 重做日志缓冲先写入文件系统缓冲, 为了 确保重做日志写入磁盘, 必须进行一次fsync操作. 由于fsync的效率取决于磁盘的性能, 因此磁盘的性能决定了事务提交的性能.

  • 4.1.2 log block

在InnoDB中, 重做日志都是以512字节进行存储的。这意味着重做日志缓冲, 重做日志都是以块的方式进行保存的. 称之为重做日志块(redo log block)每块大小512字节

  • 4.1.3 log group

log group 为重做日志组,其中有多个重做日志文件。log group 是逻辑上的概念,并没有实际的物理存储,每个log group的日志文件大小是相同的,重做日志文件中存储的是之前在log buffer 中保存的log block,因此也是以块的方式进行物理存储管理,每个块大小也是512字节。

log buffer把log block刷新到磁盘根据一下规则:

  1. 事务提交时
  2. 当 log buffer 中有一半的内存空间已经被使用
  3. log checkpoint 时

对于log block的写入追加在redo log file 的最后部分,当redo log file 被写满时,会接着写入下一个redo log file

  • 4.1.4 恢复

InnoDB存储引擎在启动时不管上一次数据库运行是否正常关闭, 都会尝试进行恢复操作. 因为重做日志记录的是物理日志, 因此恢复的速度比逻辑日志, 如二进制日志, 要快很多. 我理解的物理日志就是说 : 直接记录事务对于B+树结构和节点值的修改. 而逻辑日志是记录事务的每一句SQL语句, 事后再执行一遍还是需要改变B+树的结构. 所以物理日志比二进制日志要恢复得快

4.2 undo

  • 4.2.1 概述

数据库修改时不仅会产生 redo ,也会产生一定的undo,这样如果用户执行的事务失败了需要回滚,或者用户想要执行ROLLBACK语句,这就可以用到 undo 将数据回滚到修改之前的样子。

redo 存放在重做日志中,undo 存放在数据库内部的一个特殊段中,称为 undo 段。undo段位于共享表空间内

undo是逻辑日志,所以回滚的时候并不是物理地恢复到原来的样子,而是InnoDB执行相反的语句来实现回滚,例如:当你插入10条语句INSERT ,此时回滚就会执行10条相反的DELETE语句来删除之前执行的插入,不使用物理方法的原因是数据库是并发的,在事务回滚过程中还会有其他事务进行数据处理,所以不能单纯地以物理的手段去回滚。

undo 的另一个作用是实现MVCC当用户读取一行记录的时候,若该记录已被其他事务占用,当前事务可以通过 undo读取到之前的行版本信息,实现非锁定读取。

  • 4.2.2 group commit 

若事务非只读事务, 每次提交事务时需要进行一个fsync操作, 以此保证重做日志文件都已经写入了磁盘. 当数据库发生宕机时, 可以通过重做日志文件恢复. 磁盘的fsync性能是有限的, 当前数据库提供了group commit的功能, 即以此fsync操作确保多个事务日志被写入文件. 对于InnoDB来说, 事务提交是会进行两个阶段的动作 :

  • 修改内存中事务对应的信息, 并且将日志写入重做日志缓冲
  • 调用fsync将确保日志都从重做日志缓冲写入磁盘

有了group commit, 可以将多个事务的重做日志通过一次fsync操作就刷新到磁盘, 这样就大大减小了磁盘的压力

  • 4.2.3 Binary Log Group Commit(BLGC) 

在MySQL数据库上层进行提交时首先按照顺序将其放入一个队列中, 队列中的第一个 事务叫做leader, 其他事物称为follower, leader控制着flowwer的行为

BLGC实现方式是将事务提交的过程分为几个步骤来完成

  • Flush阶段 , 将每个事务的二进制日志写入内存中
  • Sync阶段, 将内存中的二进制日志刷新到磁盘, 若队列中有多个事务, 那么一次fsync操作就完成了二进制日志的写入
  • Commit阶段, keader根据顺序调用存储引擎事务的提交

当有一组事务在进行 Commit阶段时, 其他事务 可以进行Flush阶段
 

5.数据库提供的四种隔离级别:

  1. Read uncommitted(读未提交):最低级别,任何情况都会发生。
  2. Read Committed(读已提交):可避免脏读的发生。
  3. Repeatable read(可重复读):可避免脏读、不可重复读的发生。
  4. Serializable(串行化):避免脏读、不可重复读,幻读的发生。
     

InnoDB的默认隔离级别为REPEATABLE READ, 但是与标准SQL不同的是, InnoDB存储引擎在REPEATABLE READ事务隔离级别下, 使用Next-Key Lock锁的算法, 因此避免幻读的产生. 但是其会出现丢失 更新的现象, 若要避免丢失更新, 还是需要SERIALIZABLE的隔离级别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值