MySQL事务详解

网友投稿 740 2023-04-16

MySQL事务详解

MySQL事务详解

什么是事务?

事务是一个不可分割的工作单元,工作单元要么工作完成,要么什么也不做。从应用层面来说一个事务对应了一个完整的业务功能。从数据库层面的来讲事务就是由一批DML语句构成。

事务的分类

MySQL的InnoDB存储引擎支持扁平事务、带有保存点的事务、链事务、分布式事务

扁平事务(Flat Transactions)

扁平事务应用最为广泛,实现最为简单,扁平事务的所有操作都是在同一个层级,这些操作要么全部成功,要么全部回滚,不能存在部分提交或者部分回滚的的场景。

扁平事务

带保存点的扁平事务(Flat Transactions with Sacepoint)

扁平事务的限制就在于不能部分回滚或者提交,而有的场景是这么做是代价非常大的。比如我们举个例子:

我们玩生存类游戏,如果我们意外失败就必须从出生地开始玩,那么这会是让人崩溃的,我们希望有一个游戏存档,如果游戏失败我们可以从最近的一个存档重新加载游戏。

带保存点的扁平事务就是,除了支持扁平事务的操作外,允许事务执行过程中回滚到该事务较早的一个状态,而这个较早的状态就是保存点来记录的。

带保存点的扁平事务

链事务(Chained Transaction)

链事务是一种保存点事务的变种,两者的最大区别是,带保存点的事务可以回滚到较早前的任意保存点,而链式事务只能回滚到最近一个保存点;带保存点的事务因为需要回滚到任意保存点,固其事务执行期间所占用的资源是不会被释放的,而链事务则在执行完成当前节点后会释放掉不需要的资源,并将下一个节点需要的资源隐士传递下去。链事务可以参考Flink流式计算的Checkpoint机制,两者非常的相似。

链事务

嵌套事务(Nested Transaction)

嵌套事务顾名思义,事务结构看上去就像一棵树,根节点就是一个顶层事务,所有的叶子节点都是扁平事务(也就是说叶子节点才是真正干活儿的),事务的嵌套层级不受限制。子事务可以提交也可以回滚,但是其提交不会立即生效,只有在顶层事务提交之后所有子事务才会被真正的提交。

嵌套事务

分布式事务(Distributed Transactions)

分布式事务是指一个在分布式环境下运行的扁平事务,在本章中主要介绍本地事务,分布式事务我会在后续章节是介绍。

事务的ACID特性

A(Atomicity)原子性:整个事务操作是一个完整的不可分割的整体,只有事务中的所有操作都执行成功,事务才算执行成功,否则就要回滚到事务执行前的状态,即要么全部都做,要么全都不做。

例如:转账场景,自己账户扣除转账额度与对方账户收到转账这两个操作必须是原子的。

C(Consistency)一致性:事务将数据库从一种状态转变为另一种状态,在事务执行前和事务执行后,数据库的完整性约束没有被破坏。

例如:用户表的用户ID列有unique约束,即用户ID不可重复,如果事务执行插入了一样的用户ID,那么就产生了不一致的状态。

I(Isolation)隔离性:隔离性(又称并发控制)非常好理解,就是两个事务之间不能相互影响,即当前事务提交之前所作出的修改对其他事务都不可见,上一章我们讲到了MySQL锁,它就可以起到控制并发的作用。D(Durability)持久性:持久性是指事务一旦提交,其结果就是永久性的,即使是服务器宕机,数据也必须能够得到恢复,除了硬件故障,数据物理损坏,否则必须保证事务执行结果的永久性,也就是保证高可靠性(High Reliablility)。

事务如何实现

事务的原子性、一致性、持久性通过redo log与undo log来完成,事务的隔离性由锁与MVCC来完成。

Redo log(重做日志)

Redo log是用来实现事务的持久性,为了更好的读写性能,InnoDB会将数据缓存在内存中,对磁盘数据的修改也会落后于内存,如果进程或系统崩溃,则数据面临丢失的风险,这时重做日志就起到了保证数据的一致性与持久性作用。重做日志主要记录了以页为单位的数据修改信息,其结构如下:

redo log 结构

重做日志在Buffer中是连续写入的,Buffer中的数据会适时地刷新到物理文件中;文件顺序写入,每个事务的重做日志追加到文件末尾;单个文件大小固定,写满以后会切回到文件组的下一个文件;重做日志文件组的文件个数是固定的,写完最后一个文件则继续回到第一个文件开始写入;每个重做文件有固定2K的文件头,文件头的之后是以一个个512bytes的Block,每个Block有16bytes的头尾信息;重做日志有一个全局的日志序列号(LSN:Log Sequence Number),单调递增,表示事务写入的重做日志的字节总量,也就是一个日志偏移量。

Undo log(回滚日志)

重做日志记录了事务的行为,可以在需要的时候对页进行“重做”,但是事务有时是需要被回滚的,当语句执行失败或者用户请求回滚,就可以通过undo log将数据回滚到修改前的样子,undo log是存储了行记录的变更。其主要包含两类undo log:

两种undo log结构

下面是一个事务与undo log的关系结构:

事务与undo log关系结构

事务隔离

事务在并发场景下很难保证事务的隔离性一致性,主要有以下一些事务的并发一致性问题。

事务并发问题

针对上面的并发问题,InnoDB存储引擎通过MVCC(当然MVCC本质上也是一种乐观锁)与锁(关于锁的介绍可以阅读我的上一篇文章)来解决事务的隔离性一致性问题。

事务隔离级别

事务隔离级别是MySQL对ACID的实现程度上的分级,分为了四个等级,等级越高数据库越安全,每种隔离级别解决了不同事务并发一致性的问题,具体如下:

READ UNCOMMITTED(读未提交):这是一个最差的隔离级别,该级别下事务可以读到其它事务未提交的数据,也就是说在该事务隔离级别下会发生上述的所有并发一致性问题。READ COMMITTED(读已提交):事务只能读取到已提交的修改,也就是说多个并发的事务之间的修改是相互不可见的,该事务隔离级别解决了脏读问题。REPEATABLE READ(可重复读):该级别保证同一个事务中多次读取同一数据的结果是一致的,该级别是InnoDB默认的隔离级别,该隔离级别解决了脏读与不可重复读问题,但是仍可能出现幻读的情况(InnoDB存储引擎在该隔离级别下使用了Next-Key Lock解决了幻读问题)。SERIALIZABLE(串行化):强制事务串行化执行,没有并发,那么并发问题自然就不存在了,当然在该级别下的事务性能非常低。

关于事务隔离的实现会在后续文章详细讲解,本文不在展开。

事务的执行过程

事务的执行过程

binlog的开启时会存在一个内部XA的问题(binlog是在MySQL层,而redo log在存储引擎层),这里引入了2PC(二阶段提交):

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:列数据库是什么东东?何时应该使用它?
下一篇:MySQL中Sp运行Check表版本更新流程解析
相关文章