当前位置: 移动技术网 > IT编程>数据库>Mysql > 读MySQL技术内幕 事物笔记

读MySQL技术内幕 事物笔记

2020年07月19日  | 移动技术网IT编程  | 我要评论

读《MySQL技术内幕 InnoDB存储引擎》事物笔记
事物是数据库区别于文件系统的重要特性之一,数据库引入事物的主要目的:事物会把数据库从一种一致状态转换为另外一种一致的状态。事物的特性以及这些特性的实现方式:

事物特性 实现方式
原子性 重做日志 redo log
持久性 重做日志 redo log
一致性 回滚日志 undo log
隔离性

重做日志redo log通常是物理日志,记录的是页的屋里修改操作,回滚日志undo log是逻辑日志,根据每行记录进行记录。
事物的隔离性,通过锁技术来实现,锁分为几种:

事物隔离性 锁算法 锁范围
读未提交(read-uncommitted)
不可重复读(read-committed) 记录锁 record lock 行锁
可重复读(repeatable-read) next-key lock 锁范围
串行化(serializable) gap lock 锁范围

对于serializable这种隔离级别,完全串行化的操作,是在每个select读的数据行上,加了共享锁,相当于select *** lock in share mode,在每个变更的数据行上加上了排它锁。
repeatable-read和serializable通过主键操作数据的时候,next-key lock降级为 record lock
参考
加锁分析

redo日志

重做日志用来实现事物的持久性,由两部分组成,一是内存中的重做日志缓冲,是易失的,而重做日志文件,是持久的。当事物提交(commit)的时候,必须先将该事物的所有日志写入到重做日志文件进行持久化。当然可以通过innodb_flush_log_at_trx_commit参数配置策略,设置刷新日志的时机。

  • innodbflushlogattrx_commit = 1表示事务提交时立即将事务日志写入磁盘。
  • innodbflushlogattrx_commit = 0 表示事务提交时不立即将事务日志写入磁盘,而是由master thread每隔1秒写入磁盘文件一次,并且刷新到磁盘。这样一来,如果mysqld崩溃,那么在内存中事务日志缓冲区最近1秒的数据将会丢失,这些更新将永远无法恢复。
  • innodbflushlogattrx_commit = 2 表示事务提交时,写入文件系统的缓存中,不进行刷盘操作,在这种情况下,即使mysqld崩溃后,位于内核缓冲区的事务日志仍然不会丢失,只有当操作系统崩溃的时候才会丢失最后1秒的数据。

redo日志和二进制日志

二进制日志也就是binlog,主要用来主从复制环境的建立。

  • 首先重做日志是在InnoDB存储引擎层产生,而二进制日志是在Mysql数据库的上层产生的,任何存储引擎对于数据库的更改都会产生二进制日志,重做日志只是针对InnoDB存储引擎,其他存储引擎不一定有重做日志。
  • 其次二进制日志是一种逻辑日志,记录的是对应的sql语句,重做日志是物理格式日志,记录的是每个页的修改,因此,重做日志恢复的速度比二进制日志要快很多,因为重做日志是物理格式,所以重做日志是幂等的,而二进制日志不是幂等的。
  • 此外二进制日志只在事物提交完成后,进行一次写入,重做日志在事物进行中不断被写入。

redo block日志块

重做日志都是以512字节进行存储的,重做日志缓存、重做日志文件都是以块block的方式进行保存,每块的大小为512字节。日志块的大小和磁盘扇区的大小一样,都是512字节,因此重做日志的写入可以保证原子性,不需要doublewrite双写技术。
在这里插入图片描述
在这里插入图片描述
在InnoDB存储引擎运行过程中,log buffer根据一定的规则将内存中的log block刷新到磁盘。这个规则是:

  • 事务提交时
  • 当log buffer中有一半的内存空间已经被使用时
  • log checkpoint时
    对于log block的写入追加在redo log file的最后部分,当一个redo log file被写满时,会接着写入下一个redo log file,其使用方式为round-robin轮询调度算法。

LSN日志序列号

LSN是Log Sequence Number的缩写,其代表的是日志序列号。LSN占用8字节,并且单调递增,LSN表示的含义有:

  • 重做日志写入的总量
  • checkpoint的位置
  • 页的版本

LSN表示事务写入重做日志的字节的总量,例如:当前重做日志的LSN为1000,有一个事务T1写入了100字节的重做日志,那么LSN就变为了1100,可见LSN记录的是重做日志的总量,其单位为字节。

LSN不仅记录在重做日志中,还存在于每个页中。在每个页的头部,有一个FIL_PAGE_LSN,记录了该页的LSN。在页中,LSN表示该页最后刷新时LSN的大小。因为重做日志记录的是每个页的日志,因此页中的LSN用来判断页是否需要进行恢复操作。

例如:页P1的LSN为10000,而数据库启动时,InnoDB检测到写入重做日志中的LSN为13000,并且该事务已经提交,那么数据库需要进行恢复操作,将重做日志应用到P1页中。

undo回滚日志

在对数据库进行修改时,InnoDB存储引擎不但会产生redo,还会产生一定量的undo。这样如果用户执行的事务或语句由于某种原因失败了,又或者用户用一条ROLLBACK语句请求回滚,就可以利用这些undo信息将数据回滚到修改之前的样子。
与redo log放在文件不同,undo放在数据库内部的一个特殊段中,称为undo段,位于共享表空间中。

undo是逻辑日志,回滚时修改会被逻辑地取消,数据结构和页本身在回滚之后可能不太相同,因为这个过程中可能有其他并发的事务,比如,一个事务在修改当前一个页中某几条记录,同时还有别的事务在同一个页中另几条记录进行修改。因此,不能将一个页回滚到事务开始的样子,因为这样会影响其他事务正在进行的工作。

InnoDB存储引擎回滚时,它实际上做的是与先前相反的工作。对于每个insert,innodb存储引擎会执行一个delete;对于每一个delete,innodb存储引擎会执行一个insert;对于每一个update,innodb存储引擎会执行一个相反的update,将修改前的行放回去。

除了回滚操作,undo的另一个作用是MVCC,即在InnoDB存储引擎中MVCC的实现是通过undo来完成的。当用户读取一行记录时,若该行记录已经被其他事务占用了,当前事务可以通过undo读取之前的行版本信息,以此来实现非锁定读。

undo log会产生redo log,也就是undo log的产生会伴随redo log的产生,这是因为undo log也需要持久性的保护。
事务提交时,InnoDB会做以下两件事情:

  • 将undo log放入列表中,以供之后的purge操作
  • 判断undo log所在的页是否可以重用,若可以,分配给下个事务使用

事务提交后并不能马上删除undo log及undolog所在的页。因为可能还有其他事务需要通过undo log来得到行记录之前的版本。所以事务提交时将undo log放入一个链表中,是否可以最终删除undo log及undo log所在页由purge线程来判断。

purge清理线程

DELETE FROM t WHERE a=1;

表t上列a有聚集索引,列b上有辅助索引。对于上述的 delete操作,仅是将主键列等于1的记录delete flag设置为1,记录并没有被删除,即记录还是存在于B+树中。其次,对辅助索引上a等于1,b等于1的记录同样没有做任何处理,甚至没有产生 undo log。而真正删除这行记录的操作其实被“延时”了,最终在 purge操作中完成。
purge用于最终完成 delete和 update操作。这样设计是因为 InnoDB存储引擎支持MVCC。是否可以删除该条记录通过 purge来进行判断。若该行记录已不被任何其他事务引用,那么就可以进行真正的 delete操作。
在这里插入图片描述
history list表示按照事务提交的顺序将undo log进行组织。在InnoDB存储引擎的设计中,先提交的事务总在尾端。 undo page存放了 undo log,由于可以重用,因此一个 undo page中可能存放了多个不同事务的undo log。trx5的灰色阴影表示该 undo log还被其他事务引用。

在执行 purge的过程中, InnoDB存储引擎首先从 history list中找到第一个需要被清理的记录,这里为txl,清理之后 InnoDB存储引擎会在trx1的 undo log所在的页中继续寻找是否存在可以被清理的记录,这里会找到事务tx3,接着找到tx5,但是发现trx5被其他事务所引用而不能清理,故去再次去 history list中查找,发现这时最尾端的记录为trx2,接着找到trx2所在的页,然后依次再把事务trx6、trx4的记录进行清理。由于 undo page2中所有的页都被清理了,因此该 undo page可以被重用。

InnoDB存储引擎这种先从 history list中找 undo log,然后再从 undo page中找undo log的设计模式是为了避免大量的随机读取操作,从而提高 purge的效率

分布式事务

外部XA事物

在使用分布式事务时, InnoDB存储引擎的事务隔离级别必须设置为SERIALIZABLE。XA事务允许不同数据库之间的分布式事务,如一台服务器是 MySQL数据库的,另台是 Oracle数据库的,又可能还有一台服务器是 SQL Server数据库的,只要参与在全局事务中的每个节点都支持XA事务。

XA事务由一个或多个资源管理器(Resource Managers)、一个事务管理器(Transaction Manager)以及一个应用程序(Application Program)组成。在 MySQL数据库的分布式事务中,资源管理器就是 MySQL数据库,事务管理器为连接 MySQL服务器的客户端。
在这里插入图片描述
分布式事务使用两段式提交的方式。在第一阶段,所有参与全局事务的节点都开始准备( PREPARE),告诉事务管理器它们准备好提交了。在第二阶段,事务管理器告诉资源管理器执行 ROLLBACK还是 COMMIT。
在这里插入图片描述

内部XA事物

最常见的内部XA事务存在于binlog与InnoDB存储引擎之间,在事务提交时,先写二进制日志,再写InnoDB存储引擎的重做日志。对上述两个操作的要求也是原子的,
在这里插入图片描述
上图中,如果执行完①、②后在步骤③之前MySQL数据库发生了宕机,则会发生主从不一致的情况。为了解决这个问题,MySQL数据库在binlog与InnoDB存储引擎之间采用XA事务。当事务提交时,InnoDB存储引擎会先做一个PREPARE操作,将事务的xid写入,接着进行二进制日志的写入,如下图所示。如果在InnoDB存储引擎提交前,MySQL数据库宕机了,那么MySQL数据库在重启后会先检查准备的UXID事务是否已经提交,若没有,则在存储引擎层再进行一次提交操作。
在这里插入图片描述
在这里插入图片描述

不好的事物习惯

  • 在循环中提交事物
  • 使用自动提交事物
  • 使用自动回滚事物
  • 使用执行时间较长的事物

本文地址:https://blog.csdn.net/lihuayong/article/details/107303785

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网