数据库事务系列-MySQL跨行事务模型

说来和MySQL倒是有缘,毕业的第一份工作就被分配到了RDS团队,主要负责把MySQL弄到云上做成数据库服务。虽说整天和MySQL打交道,但说实话那段时间并没有很深入的理解MySQL内核,做的事情基本都是围绕着MySQL做管控系统,比较上层。好在周边都是MySQL内核神级人物,在他们的熏陶下多多少少对MySQL的一些基本知识有一些零碎的记录和模糊的认识,这些基础对于今天整理理解MySQL跨行事务模型非常重要。更重要的,有很多不解的地方也可以向大神请教。

MySQL事务模型在网上也有很多的介绍,在写这篇文章之前本人也翻看了很多资料作为参考,以期让自己理解的更加深入全面。看了大多数介绍文章之后发现部分文章并不完整,比如有的只介绍了几种隔离级别下MySQL的表现,并没有从技术角度进行解读。有的文章说的倒很全面,但缺乏些许条理,读起来并不容易理解。这也是笔者希望能够带给大家一点不一样的东西,从技术角度进行解读,并且利于理解。

MySQL事务原子性保证

事务原子性要求事务中的一系列操作要么全部完成,要么不做任何操作,不能只做一半。原子性对于原子操作很容易实现,就像HBase中行级事务的原子性实现就比较简单。但对于多条语句组成的事务来说,如果事务执行过程中发生异常,需要保证原子性就只能回滚,回滚到事务开始前的状态,就像这个事务根本没有发生过一样。如何实现呢?

MySQL实现回滚操作完全依赖于undo log,多说一句,undo log在MySQL除了用来实现原子性保证之外,还用来实现MVCC,下文也会涉及到。使用undo实现原子性在操作任何数据之前,首先会将修改前的数据记录到undo log中,再进行实际修改。如果出现异常需要回滚,系统可以利用undo中的备份将数据恢复到事务开始之前的状态。下图是MySQL中表示事务的基本数据结构,其中与undo相关的字段为insert_undo和update_undo,分别指向本次事务所产生的undo log。

数据库事务系列-MySQL跨行事务模型

事务回滚根据update_undo(或者insert_undo)找到对应的undo log,做逆向操作即可。对于已经标记删除的数据清理删除标记,对于更新数据直接回滚更新;插入操作稍微复杂一些,不仅需要删除数据,还需要删除相关的聚集索引以及二级索引记录。

undo log是MySQL内核中非常重要的一块内容,涉及知识比较多而且复杂,比如:

1. undo log必须在数据修改之前持久化,undo log持久化需不需要记录redo以防止宕机异常?如果需要就又涉及宕机恢复…

2. 通过undo log如何实现MVCC?

3. 那些undo log可以在什么场景下回收清理?如何清理?

MySQL事务一致性保证:强一致性事务保证 MySQL事务隔离级别 Read Uncommitted(RU技术解读:使用X锁实现写写并发)

Read Uncommitted只实现了写写并发控制,并没有有效的读写并发控制,导致当前事务可能读到其他事务中还未提交的修改数据,这些数据准确性并不靠谱(有可能被回滚掉),因此在此基础上作出的一切假设就都不靠谱的。在现实场景中很少有业务会选择该隔离级别。

写写并发实现机制和HBase并无两样,都是使用两阶段锁协议对相应记录加行锁实现。不过MySQL中行锁机制比较复杂,根据行记录是否是主键索引、唯一索引、非唯一索引或者无索引等分为多种加锁情况。

1. 如果id列是主键索引,MySQL只会为聚簇索引记录加锁。

2. 如果id列是唯一二级索引,MySQL会为二级索引叶子节点以及聚簇索引记录加锁。

3. 如果id列是非唯一索引,MySQL会为所有满足条件(id = 15)的二级索引叶子节点以及对应的聚簇索引记录加锁。

4. 如果id列是无索引的,SQL会走聚簇索引全表扫描,并将扫描结果加载到SQL Server层进行过滤,因此InnoDB会为扫描过的所有记录先加上锁,如果SQL Server层过滤不符合条件,InnoDB会释放该锁。因此InnoDB会为扫描到的所有记录都加锁,很恐怖吧!

接下来无论是RC、RR,抑或是Serialization,写写并发控制都使用上述机制,所以不再赘述。接下来会重点分析RC和RR隔离级别中的读写并发控制机制。

在详细介绍RC和RR之前,有必要在此先行介绍MySQL中MVCC机制,因为RC和RR都使用MVCC机制实现事务之间的读写并发。只不过两者在实现细节上有一些区别,具体区别接下来再聊。

MVCC in MySQL

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/f03e053165f468b310118e0452b6870d.html