最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

InnoDB事务

运维笔记admin55浏览0评论

InnoDB事务

InnoDB事务

1. 支持的事务

扁平事务:所有操作都处于同一层次

带保持点的扁平事务:事务能够回到保持点的状态。

链事务:系统崩溃时,所有保存点都将消失。

嵌套事务:具有层次结构(树)。任意一个事务回滚会引起它的所有子事务一同回滚。并不原生支持。

分布式事务

2. 事务的实现

事务的隔离性由锁实现
redo log 用来保证事务持久性
undo log 用来保证一致性、原子性

redo 是恢复提交事务修改的页操作,undo 回滚行记录到某个特定版本
redo 通常记录的是页的物理修改操作; undo 是逻辑日志,根据每行记录进行记录

2.1 redo

功能:保证事务的持久性。基本是顺序写。由存储引擎生成。

包含两部分:redo log缓存(内存中), redo log文件

(1)事务提交时,必须先将该事务的所有log写入到redo log文件中,才算完成COMMIT操作。
为了确保重做日志写入磁盘,需要调用一次fsync操作

innodb_flush_log_at_trx_commit控制redo log刷新到磁盘的操作。
0表示,事务提交时不进行写入日志文件的操作。(写入日志文件由master thread完成)
1表示,写入日志文件,并调用fsync。(默认设置)
2表示,写入日志文件,不调用fsync(在文件系统缓存中)

(2)binlog 日志,用来进行PONIT-IN-TIME(PIT)的恢复及主从复制环境的建立。
由MySQL的上层产生,逻辑日志,记录的是对应的SQL语句。只在事务提交完成后进行一次写入。

(3)以 block 方式保存,大小为512字节
日志块头,12字节
日志内容,492字节
日志块尾,8字节

(4)log group 由多个redo log文件组成,每个日志文件的大小相同

将内存中的log block刷新到磁盘的时机:
事务提交时
当log buffer中有一半的内存空间已经被使用时
log checkpoint 时

(5)以append的方式写入redo log file的最后部分,当写满时,接着写入下一个redo log file
每个redo log file的前2KB部分不保存log block的信息。

log group在的第一个 redo log file保存了log file header等信息,在写入后续日志时可能需要更新该部分信息,因此对redo log file的写入并不是完全顺序的。

(6)redo log格式

redo log type 为重做日志的类型
space 为表空间ID
page_no:页的偏移量


(7)LSN,占用8字节
其代表的含义为:
重做日志写入总量
checkpoint的位置
页的版本

每个页中FIL_PAGE_LSN表示该页最后刷新时的LSN。

2.2 undo

此处可参考: link

帮助事务回滚和MVCC的功能。需要随机读写

undo log存放在** undo 段**中

undo是逻辑日志,例如,对每个INSERT,会进行一个DELETE。

undo会产生redo log

(1)InnoDB存储引擎有 rollback segment,每个回滚段有1024个undo log segment,在undo log segment中进行undo页的申请。

在undo log segment分配页并写入undo log的过程,同样需要写入redo log。

(2)具体组织方式:Undo Tablespace

要求:每个写事务开始写操作之前都需要持有一个Undo Segment

Undo Tablespace 中最多可有 128 个 Rollback Segment Header,并且有 Rollback Segment Arrary Header,类似指针数组,指向各个Rollback Segment Header;

每个 Rollback Segment Header 中包含了 History List,还有 1024 个 Slot,指向每个 Undo Segment。

每个 Undo Segment 会持有至少一个 Undo Page ,并且该段下的第一个 Undo Page 会有 Undo Page Header 和 Undo Segment Header,剩余的空间都是用来存放Undo Log的

(3)当事务提交时
将undo log放入链表中,以供之后的purge操作
判断undo log所在的页能否重用,若可以分配给下一个事务使用。

事务提交后并不能马上删除undo log及其所在的页,这是因为可能会被MVCC使用。
事务提交时,判断undo页的使用空间是否小于3/4,若是则表示该undo页可以被重用。

(4)undo log 格式
insert undo log 在事务提交后直接删除。

update undo log 可能需要提供MVCC机制,不能在事务提交时删除。

上图中的n_unique_index是记录的主键部分(变长部分,主键可以有多列),通过记录的主键可以找到该行记录。

update vector中记录的就是当前这个Record版本相对于其之后的一次修改的Delta信息

DATA_TRX_ID是历史版本记录的事务IDtrx_id,而非当前修改事务的。

(5)隐藏列中的roll_pointer,就是指向undo log中该行旧版本的记录

这也是为什么update undo log中trx_idroll_ptr存在的目的,这些记录可以组成链表。

对 MVCC 读语句会有 Read View,其记录了当前活跃事务ID列表及下一个开始事务的ID,因此可将事务分为:已经提交事务(min_trx_id,当前活跃事务列表中的最小值),正活跃事务列表(m_ids),未开始事务(max_trx_id)。

通过行记录的trx_id来判断对creator_trx_id(创建Read View的事务ID)是否可见。可分为三种情况:

  1. trx_id < min_trx_id 或者 trx_id 不在 m_ids 中,说明创建这个版本的记录的事务已提交,对当前事务可见。
  2. trx_id > max_trx_id,说明是在创建 Read View 之后才开启的事务,不可见。
  3. trx_id 在 m_ids 中,说明处于创建该版本的事务活跃状态未提交,不可见。

这里之所以还需要考虑是否在 m_ids 内,是因为事务提交并非按顺序进行,事务ID的分配是自增长的。即当前活跃事务可能为T2,T4,T5,此时说明比T2小的已经提交了,T3也提交了,因此要进行这种判断。

(6)ROLLBACK时的操作,从后向前依次读取Undo Record

(7)Undo log 的删除

事务结束时,会分配一个trx_no,是自增长的,维护了事务的提交顺序。

在创建Read View时,会通过头插法插入一个全局链表时,事务结束时,会从链表中进行删除。

因此该链表的尾部就是最老的视图,其记录的trx_nom_low_limit_no

若某个事务的trx_no < m_low_limit_no,则表明该事务在 当前所有活跃事务创建Read View 之前就已经提交,那么就可以删除该事务的Undo log。

注意:此处有个不太直观的地方,要区分好 Undo Log 的trx_id 对应的 trx_no 及 产生该 Undo Log 的事务的 trx_no

例如:假设有个空表,事务ID为45的向其中插入2条数据,产生的Insert Undo Log在该事务提交后就被删除了,其trx_no假设为1。
trx_id,a,value
45,1,1
45,2,1
事务ID为46的更改上述数据,
trx_id,a,value —————— Undo Log 1
46,1,2 ————————> 45, 1, 1
45,2,1
需要注意的是,这个 Undo Log 1 是放在事务ID为 46 的 Update Undo Log 中,其正常提交后,trx_no为2。
trx_id,a,value —————— Undo Log 2 —————— Undo Log 1
47,1,3 ————————> 46,1,2 ————————> 45,1,1
Undo Log 2是在事务ID为 47 的 Update Undo Log,其正常提交后,trx_no为3。
如果开启新的写事务的话,其看到的最大的 trx_no 为 3 ,而trx_no为2的事务产生的Undo Log可以被删除,从上也可知删除Undo Log 1不会产生影响。

因此,通过上述删除策略,表中的记录要么是只有聚集索引Index中的版本,要么还有至少一个Undo历史版本,所有的读事务都一定能被Index中的版本或者历史版本满足。

2.3 purge

purge用于最终完成delete和update操作

若该行记录已经不被其他任何事务引用,那么就可以进行真正的delete操作。

(1)事务提交时,会将 Undo log header 以头插法的方式插入到 History List 中。

(2)先从History List中找 undo log,再从undo page中找undo log的设计避免了大量的随机读取操作。

2.4 group commit

将多个事务的缓存中的redo log通过一次fsync刷新到磁盘中

3. 事务

3.1 事务控制

SAVEPOINT identifier;创建保存点
ROLLBACK TO SAVEPOINT identifier;回滚到一个不存在的保存点时,会抛出异常

因为某条语句失败抛出异常时,不会自动回滚,需要用户决定提交或回滚。

3.2 隐式提交的SQL语句

ALTER TABLE、CREATE TABLE/INDEX、DROP TABLE/INDEX、TRUNCATE TABLE等,执行完这些语句后,会有一个隐式的COMMIT操作,代表这些语句不能被回滚。

3.3 事务操作统计

com_commitcom_rollback会统计 显式提交或回滚 的事务数量

3.4 事务隔离级别

在SERIALIABLE级别,InnoDB会对每个SELECT语句自动加上LOCK IN SHARE MODE;

在READ COMMITTED级别下,除了唯一性或外键约束检查需要gap lock,其余都不会使用gap lock。

3.5 分布式事务

在使用分布式事务时,InnoDB 必须设置隔离级别为 SERIALIABLE

XA事务由一个或多个资源管理器、一个事务管理器以及一个应用程序组成。

3.6 好的事务习惯

最好把事务的START TRANSACTION、COMMIT、ROLLBACK操作交给程序端来完成,而不是在存储过程中完成。

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论