内容简介:本文主要是针对《Mysql技术内幕:InnoDB 存储引擎》一书中第七章关于 InnoDB 存储引擎中事务的学习总结。事务是访问并更新数据库各种数据项的一个程序执行单元,是数据库区别于文件系统的重要特性之一。理论上,事务必须满足 ACID 特性,才算严格的定义,其中对于 InnoDB 存储引擎来说,其默认事务隔离级别为 READ REPEATABLE,完全遵循和满足事务的 ACID 特性。
本文主要是针对《Mysql技术内幕:InnoDB 存储引擎》一书中第七章关于 InnoDB 存储引擎中事务的学习总结。
事务是访问并更新数据库各种数据项的一个程序执行单元,是数据库区别于文件系统的重要特性之一。
事务的 ACID 特性
理论上,事务必须满足 ACID 特性,才算严格的定义,其中对于 InnoDB 存储引擎来说,其默认事务隔离级别为 READ REPEATABLE,完全遵循和满足事务的 ACID 特性。
- A(Atomicity) 原子性
一个事务必须被视为一个不可分割的最小工作单元,要么全部提交成功,要不全部失败回滚 复制代码
- C(Consistency) 一致性
一致性是指数据库从一个执行性状态转换为另外一个一致性状态 事务的一致性是希望所有操作是符合现实当中的期望的,比如事务的结束后,完整性约束有没有被破坏,是否发生丢失更新,脏读,不可重复读等问题 所以事务的一致性是一个综合的概念,要靠事务的原子性,隔离性和持久性来保证 复制代码
- I(Isolation) 隔离性
隔离性是指事务所做的修改在最终提交前,对其它事务是不可见的,通常是靠锁机制来实现的 复制代码
- D(Durability) 持久性
事务一旦提交,,其所做的修改是永久保存在数据库里的,即使系统奔溃数据页不会丢失 持久性保证事务系统的高可靠性,而高可用性事务本身无法保证,需要一些系统共同配合完成 复制代码
事务的分类
事务分为扁平事务,带有保存点的扁平事务,链事务,嵌套事务,分布式事务。对于 InnoDB 存储引擎来说,其支持扁平事务,带保存点的事务,链事务,分布式事务。对于嵌套事务,其原生不支持
- 扁平事务
- 扁平事务由 BEGIN WORK 开始,ROLLBACK 或者 COMMIT 结束,其间是原子的,要么执行,要么回滚 复制代码
- 带有保存点的扁平事务
- 除了支持扁平事务支持的操作外,允许在事务执行过程中回滚同一事务中较早的一个状态 - 因为某些事务可能在执行过程中出现的错误并不会导致所有的操作都无效,放弃整个事务不合乎要求,开销太大 - 保存点用来通知事务系统应该记住事务当前的状态,以便当之后发生错误时,事务能回到保存点当时的状态 复制代码
- 链事务
- 链事务的思想是:在提交一个事务时,释放不需要的数据对象,将必要的处理上下文隐式地传给下一个要开始的事务 - 提交事务操作和开始下一个事务操作 将合并为一个原子操作,这意味着下一个事务将看到上一个事务的结果,就好像一个事务中进行的一样 - 链事务与带有保存点的扁平事务不同的是,带有保存点的扁平事务能回滚到任意正确的保存点,而链事务中的回滚仅限当前事务,即只能恢复到最近的一个保存点 - 对于锁的处理,两者也不相同,锁事务在执行 COMMIT 后即释放了当前所持有的锁,而带有保存点的扁平事务不影响迄今为止所持有的锁 复制代码
- 嵌套事务
- 嵌套事务是一个层次结构框架,由一个顶层事务控制着各个层次的事务,顶层事务之下嵌套的事务被称为子事务 - 嵌套事务是由若干事务组成的一棵树,子树既可以是嵌套事务也可以是扁平事务 - 处在叶节点的事务是扁平事务,但是每个事务从根到叶节点的距离可以是不同的 - 子事务既可以提交也可以回滚。但是它的提交操作并不马上生效。除非其父事务已经提交。因此可以推论出,任何子事务都在顶层事务提交后才真正的提交 - 树中的任意事务回滚会引起它的所有子事务一同回滚,故子事务仅保留 ACI 特性而不具有 D 特性 - 实际的工作是交由叶子节点完成,即只有叶子节点的事务才能才能访问数据库、发送信息、获取其他类型的资源,而高层的事务仅负责逻辑控制 复制代码
- 分布式事务
- 分布式事务通常是一个分布式环境下运行的扁平事务,因此需要根据数据所在位置访问网络中的不同节点 - 分布式事务一般不能通过一台数据库就完成任务,其需要访问网络中两个节点或者多个的数据库,而在每个节点的数据库执行的实务操作有都是扁平的 - 对于分布式事务,其同样需要满足ACID特性,要么都发生,要么都失败 复制代码
事务的实现
事务的隔离性是通过锁来实现的,而原子性,一致性,持久性是通过数据库中的 redo log 和 undo log 来实现的。
redo log
- 重做日志由两部分组成:内存中中的重做日志缓存和磁盘上的重做日志文件
- InnoDB 存储引擎的重做日志是在事务进行中不断的写入,并不是在事务提交时才写入,先写入重做日志缓存,然后根据一定规则刷新到重做日志文件
- 重做日志文件记录了 InnoDB 存储引擎的事务日志,主要用来在发生宕机的情况下,对事务操作进行恢复操作,从来保证的原子性和持久性
- 重做日志缓存:
- 重做日志缓存不放在缓存池中,是另外一份单独的缓存 - 重做日志缓存不需要特别大,因为 Master Thread 每秒都会将数据刷新到磁盘 - 通过参数 innodb_log_buffer_size 来修改重做日志缓存的大小,默认为 8MB - 重做日志缓存都会被刷新到磁盘的三种条件:1. Master Thread 会每秒进行刷新 2. 每个事务提交时会刷新 3.重做日志缓存空间小于 1/2 时会强制刷新 复制代码
- 重做日志文件:
- 重做日志文件至少有一个重做日志文件组,每个重做日志文件组至少有 2 个重做日志文件 - 为了保证高可用性,可以设置镜像日志文件组,将日志组存储在不同的磁盘上 - 重做日志的写入不需要 doublewrite,因为写入是按照一个扇区的大小进行写入的,是写入的最小单位,所以可以保证写入的可靠性 复制代码
undo log
- undo log 主要用于用户在执行 rollback 语句时进行回滚操作
- redo 存放在日志文件里,而 undo存放在数据库共享表空间的一个是特殊段中(undo segment)
- undo 是逻辑日志,在回滚时所有修改逻辑的被取消了,但是数据结构和页本身在回滚后可能大不相同
- undo 其实就是做与先前相反的操作,对于每个 Insert 执行 delete,对每一个 update 执行相反的 update
- undo 另外一个作用是实现 MVCC(多版本控制),实现非锁定读,通过 undo 日志找到之前的行版本信息
- uodo log 也会产生 redo log,因为 undo log 也需要持久性的保护
- undo log 的回收和删除
- 并不是当事务提交时,undo log 就会被删除,很有可能还有其他事务在使用该 undo log 来记录之前的版本 - 所以事务提交时 undo log 会被放在待删除列表里,之后通过 purge 线程来根据是否有其它事务在使用来决定删除 - 对于 insert 操作的记录,只对本事务可见,所以在事务提交后可以直接删除,不需要进行 purge 操作 - 通过全局参数 innodb_purge_batch_size 来设置每次 purge 操作可以清理的 undo 页的数量 复制代码
事务控制语句
- Mysql 命令行的默认设置下,事务是自动提交的,可以通过执行命令 SET AUTOCOMMIT = 0 来禁止自动提交
- 关于事务的控制语句总结如下:
- START TRANSACTION | BEGIN:显式地开启一个事务 - COMMIT:会提交事务,并使得已对数据库做的所有修改成为永久性的 - COMMIT WORK:COMMIT WORK 和 COMMIT 语句基本是一致的,不同之处在于 COMMIT WORK 用来控制事务结束后的行为是 CHAN 还是 RELEASE 的 用户可以通过参数 completion_type 来进行控制 COMMIT WORK 的行为,该参数默认为 0,在这种设置下 COMMIT和 COMMIT WORK是完全等价的。 当参数 completion_type的 值为 1 时, COMMIT WORK 等同于 COMMIT AND CHAIN,表示马上自动开启个相同隔离级别的事务 - ROLLBACK:回滚并结束用户的事务,并撤销正在进行的所有未提交的修改 - ROLLBACK WORK:ROLLBACK WORK 和 ROLLBACK 的关系与 COMMIT WORK 和 COMMIT 关系类似 - SAVEPOINT identifier: SAVEPOINT 允许在事务中创建一个保存点,一个事务中可以有多个 SAVEPOINT - RELEASE SAVEPOINT identifier:删除一个事务的保存点,当没有一个保存点执行这句语句时,会抛出一个异常 - ROLLBACK TO [SAVEPOINT] identifier:这个语句与 SAVEPOINT 命令一起使用,可以把事务回滚到标记点,而不回滚在此标记点之前的任何工作 - SET TRANSACTION:这个语句用来设置事务的隔离级别。 InnoDB存储引擎提供的事务隔离级别有: READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、 SERIALIZABLE。 复制代码
- ROLLBACK TO SAVEPOINT 来回滚到某个保存点,但是如果回滚到一个不存在的保存点,会抛出异常
- ROLLBACK TO SAVEPOINT 虽然有 ROLLBACK,但其并不是真正地结束一个事务,因此即使执行了 ROLLBACK TO SAVEPOINT ,之后也需要显式地运行 COMMIT 或 ROLLBACK 命令
- 通过变量 com_commit 和 com_rollback 可以查看每秒钟事务的提交量和回滚量,这个统计是所有显式提交的事务
事务的隔离级别
在文章 InnoDB 存储引擎的锁学习 中就多次提到事务的隔离级别,不同粒度的锁在不同隔离级别下的表现。隔离级别越低,数据库所需要的锁越少,性能越好,但是安全性越低。接下来是对事务的四种隔离级别(由低到高)的总结:
- Read Uncommitted(读取未提交内容)
- 在该隔离级别,所有事务都可以看到其他未提交事务的执行结果 - 本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少 - 读取未提交的数据,也被称之为脏读问题 - 该隔离级别违背了事务的隔离性原则 复制代码
- Read Committed(读取提交内容)
- 一个事务只能看见已经提交事务所做的改变,满足隔离性的定义 - 该隔离级别下会出现同一个事务两次读同一份数据结果不一致现象,也就是不可重复读问题 复制代码
- Repeatable Read(可重读)
- 这 是 MySQL 的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行 - Repeatable Read 这会导致幻读 (Phantom Read)问题。幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。 - InnoDB 利用 Gap Lock 算法在 Repeatable Read 隔离级别下解决了 幻读现象 复制代码
- Serializable(可串行化)
- 这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。 - 它是在每个读的数据行上加上共享锁,在这个级别,可能导致大量的超时现象和锁竞争。 复制代码
不好的事务习惯
- 在循环中提交事务
- 当插入发生错误时,数据库会停留在一个未知的位置,无法回滚 - 每一次提交都要写一次重做日志,性能会变的很差 CREATE PROCEDURE load1(count int unsigned) begin declare s int unsigned default 1; declare c char(80) default repeat('a',80); while s<=count do insert into t1 select NULL,c; commit; set s=s+1; end while; end; 复制代码
- 使用自动提交事务
- 自动提交并不是好习惯,会让一些开发人员可能产生错误的理解 - 另外,在不同的语言API时,自动提交是不同的,用不同的语言来编写数据库应用程序前,应该对连接MySQL的API做好研究 - 在编写应用程序开发时,最好把事务的控制权限交给开发人员,即在程序端进行事务的开始和结束 复制代码
- 使用自动回滚
- 自动回滚的情况下,开发人员无法定位发生了什么样的错误 - 对于事务的 BEGIN,COMMIT,ROLLBACK 操作应该交给程序端来控制,当发生错误时,我们可以把异常抛出去再进行回滚 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Clojure软件事务存储器
- InnoDB存储引擎之事务和可靠性
- PostgreSQL 11 发布:JIT、存储过程事务,并行性能提升
- PostgreSQL 11 支持 JIT、存储过程事务,并行性能提升
- SQL Server存储过程中编写事务处理的方法小结
- Java事务解析(事务的基本操作+隔离的等级+事务的四大特性+事务的概念)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
API Design for C++
Martin Reddy / Morgan Kaufmann / 2011-2-18 / USD 59.95
The design of application programming interfaces can affect the behavior, capabilities, stability, and ease of use of end-user applications. With this book, you will learn how to design a good API for......一起来看看 《API Design for C++》 这本书的介绍吧!