目录
八 事务
事务由一个或多个简单的SQL语句组成,在一个事务中的操作,要么全部成功,要么全部失败。
通常,数据库事务具有ACID特性,但一些数据库出于各种目的并没有严格满足事务的ACID特性,比如Oracle的默认事务隔离级别是READ COMMITTED,不满足隔离的特性。
(一)事务的分类
事务可以分为以下类型:
- 扁平事务
- 带有保存点的扁平事务
- 链事务
- 嵌套事务
- 分布式事务
1 扁平事务
扁平事务是最简单的事务,也是使用最频繁的事务。在扁平事务中,所有操作都处于同一层次,有BEGIN开始,由COMMIT或ROLLBACK结束,事务中的操作是满足原子特性的。
扁平事务在回滚时是恢复到事务开始时的状态。
2 带有保存点扁平事务
允许事务在执行过程中回滚到同一事务中的某一时刻的状态,通过保存点机制来通知数据库系统记住事务的状态,以便发生错误时进行回滚。
扁平事务实际上是拥有一个默认保存点的,即事务开始时的状态。
3 链事务
是保存点事务的一个变种,当系统崩溃时,保存点丢失,在这时进行恢复需要从事务开始处执行,链事务在提交时,将处理的上下文隐式传给下一个要开始的事务,这样一来,每个事务之间就像用链穿了起来,但在恢复时只能恢复到当前事务开始的状态。
4 嵌套事务
嵌套事务是一个层次结构的框架,由顶层事务控制着各个层次的事务,嵌套事务的定义如下:
- 嵌套事务是由若干事务组成的一棵树,子树既可以是嵌套事务,也可以是扁平事务。
- 处在叶节点的事务是扁平事务,但是每个子事务从根到叶的距离可以是不同的。
- 位于根节点的事务称为顶层事务,其他事务为子事务,事务的前驱节点为父事务,后继节点为儿子事务。
- 子事务既可以提交也可以回滚,但子事务的提交不会马上生效,除非它的父事务提交,因此,任何子事务都必须在顶层事务提交后才会真正提交。
- 树中任意一个事务的回滚会引起它的所有子事务的回滚。
5 分布式事务
在分布式环境下的扁平事务,在数据库分库分表时需要特别关注。
(二)事务的实现
事务的持久性是通过redo log保证的,事务的一致性是通过undo log保证的。redo log是物理日志,记录的是也得物理修改,undo log是逻辑日志,根据每行记录进行记录。
1 redo
redo log存放在重做日志文件中,用来实现事务的持久性,其由两部分组成,一是内存中的日志缓冲;二是磁盘中的日志文件。
当事务提交时,首先将重做日志写入到日志文件中在将数据刷新到磁盘上,由于重做日志缓冲先写入文件系统缓存中,为了确保写入磁盘,则必须进行一次fsync操作,也可以通过innodb_flush_log_at_trx_commit控制日志刷新到磁盘的策略,默认为1,即事务提交后必须调用一次fsync操作;0表示事务提交后不写入日志,由Master Thread定期写入;2表示写入时只写入文件系统缓存,不调用fsync,这种情况下可能会导致数据丢失。
重做日志缓冲、重做日志文件都是以块的形式存放的,每个块的大小为512字节。
2 undo
undo日志用于事务的回滚,当对数据库进行修改时,InnoDB不但会产生redo日志,还会产生undo日志。undo日志存放在数据库共享表空间的Rollback Segment中。
undo日志进行回滚是对某一事务的回滚,由于数据库系统是并发的,因此undo日志并不一定能将数据库回滚到初始状态,通过undo日志的回滚不会影响其他正在进行中的事务。
除了回滚操作,undo日志的另一个作用是MVCC,读取数据快照是通过undo来完成的。
注意:undo log也会产生redo log,因为undo log也需要持久化。
3 purge
delete和update操作可能并不直接删除原有的数据,只是进行标志位的变更,记录仍然存在于B+树中,真正的删除操作在purge操作中进行,这样设计的目的是支持MVCC,所以记录不能在事务提交时立即进行处理,当该记录不被任何其他事务引用才可以进行处理。
4 group commit
若事务为非只读事务,则每次事务提交后需要进行一次fsync操作,来保证重做日志写入磁盘,为了提高磁盘fsync的效率,当前的数据库都提供了group commit的功能,即一次将多个事务的重做日志刷新至磁盘。
(三)事务的隔离级别
SQL标准定义的四个隔离级别:
- READ UNCOMMITTED:事务中的修改,即使没有提交,也可以被其他事务看到,会导致“脏读”、“幻读”和“不可重复读取”
- READ COMMITTED:保证了一个事务不会读到另一个事务已修改但未提交的数据,避免了“脏读取”,但不能避免“幻读”和“不可重复读取”。
- REPEATABLE READ:一个事务不可能更新由另一个事务修改但尚未提交(回滚)的数据。可以避免脏读和不可重复读,但无法避免幻读,是MySql的默认隔离级别
- SERIALIZABLE:这种隔离级别是所有的事务都在一个执行队列中,依次顺序执行,而不是并行。可以避免脏读、不可重复读、幻读。但是这种隔离级别效率很低,因此,除非必须,否则不建议使用。
(四)分布式事务
1 外部事务
InnoDB存储引擎提供了对XA事务的支持,并通过XA事务来支持分布式事务的实现。
XA事务有一个或多个资源管理器、一个事务管理器以及一个应用程序组成:
- 资源管理器:提供访问事务资源的方法,通常一个数据库就是一个资源管理器
- 事务管理器:协调参与全局事务中的各个事务,需要和参与全局事务的所有资源管理器进行通信
- 应用程序:定义事务的边界,执行全局事务中的操作
在MySql数据库的分布式事务中,资源管理器是MySql数据库,事务管理器是连接MySql服务器的客户端,如下图:
分布式事务使用两阶段提交(2PC)的方式。
2 内部事务
内部事务指写二进制日志和写InnoDB重做日志,MySql通过内部XA保证一致性,如下图所示:
特此声明:本系列博客为均为《MySql技术内幕 InnoDb存储引擎》读书笔记,存在错误还请指正
参考资料
《MySql技术内幕 InnoDb存储引擎》