【2019秋冬】【MySQL】第七章 事务

事务会把数据库从一种状态转换至另一种一致状态
在数据库提交工作时,要么保证所有修改都保存了,要么所有修改都不保存

锁讨论隔离性,事务保障原子性

事务是访问并更新数据库中各种数据的一个程序执行单元
要么都修改,要么不做

ACID特性
A atomicity 原子性
整个操作是整体性的,不能做一半结束了或者中途错误了还继续执行

C consistentcy一致性
事务将数据库从一种状态转移至另一种状态,数据库的完整性不被破坏

I isolation 隔离性
每个读写事务的对象对其他事务的操作对象互相分离,不可见,通过锁完成

D durability 持久性
事务提交后,结果是永久性的,保证可靠性

事务可分为5类
1.扁平事务
最简单,使用最频繁的一种。所有操作都属于同一层次,begin work开始,commit work或 rollback work结束,要么都执行,要么都回滚
是应用程序原子性的基本组成模块
缺点是不能提交或回滚事务的一部分,或分步骤提交
2.带有保存点的扁平事务
在扁平事务基础上,设置保存点(save work)允许执行过程中回滚到同一事物的较早状态
默认会在最开始设置一个隐式保存点,之后的保存点序号递增,回滚后序号接着增长,不会回到1,例如当前在4,要求混滚到2,下一个点序号是5,不是3。如果想完全回滚就rollback work两次
3.链事务
保存点模式的变种,因为保存点易丢失,如果全丢失了就要从头恢复提交
链事务:提交一个事务时,把必要处理的上下文隐式传给下一个事务,当前提交事务和下一个事务看做一个原子操作,下一个事务可以看到上一个事务的结果,整体看起来就是一个事务(个人理解就是把事务分成多个小事务,然后像链表一样串他)
链事务只能回滚到最近一个保存点
4.嵌套事务
树结构,根节点为顶层事务,其他都为子事务
叶子节点必为扁平事务,事务的前驱叫父事务,下一层是子事务
子事务可以回滚,但必须在父事务提交后,树中任意一个事务回滚会引起他所有子事务的回滚
实际工作是有叶子节点完成的,高层事务负责逻辑控制
5.分布式事务
在分布式环境下运行的扁平事务

事务的实现
隔离性通过锁实现
原子性,一致性,持久性通过redo log和undo log完成
redo恢复提交事务修改的操作,物理日志
undo回滚行记录到某个版本,逻辑日志

redo
包括 redo log buffer 重做日志缓存 和 redo log file 重做日志文件
buffer 缓存在内存中,易丢失;file 持久

InnoDB通过Force Log at Commit机制实现持久性,当事务Commit的时候,必须先将事务的所有redo log buffer和 undo log buffer 写入 redo log file 和 undo log file,再等待事务的Commit完成才结束

插入:理解undo和redo
张三要删除自己的记录,redo记录的是张三删除这个操作,undo记录的是张三删除的数据。
这些操作都是在缓存中完成的,缓存是在CPU里,掉电丢失,不持久,所以为了保证持久性,需要放进硬盘中(磁盘),所以要从数据变成文件保存去磁盘,掉电了也可以恢复

fsync 同步内存中所有已修改的文件数据到储存设备

为了保证每次日志都写入重做日志文件,在每次 redo log buffer 写入 redo log file后,都调用一次fsync操作(因为redo log buffer会先写入文件系统缓存,为了确保redo log会写入磁盘,必须进行一次fsync)

InnoDB可以手动控制是否写入
参数 innodb_flush_log_at_trx_commit
默认1:事务提交时必须调用一次fsync
0:事务提交时不调用fsync,通过master thread的每1秒进行一次fsync完成
2:提交时重做日志仅写入文件的缓存,不进行fsync操作。这样的结果是当操作系统掉电时数据会丢失,数据库宕机不丢失

二进制日志(binlog)是在数据库上层产生,并不只针对InnoDB,其他存储引擎对数据库的更改都会改变日志
二进制日志是逻辑日志,对应SQL语句;只在事务提交完成后写入一次,顺序固定
InnoDB的重做日志记录的是对页的修改;在事务进行时不断的写入,并发,顺序不固定

重做日志以块block形式保存,称为日志块 redo log block,每块512字节
若一个页中重做日志大小大于512字节,要分割为多个重做日志
重做日志还包括 日志块头(log block header)12字节,日志块尾(log block tailer)8字节,所以实际上能存492字节(512-20)

重做日志组(log group)
逻辑上的概念,包括多个 redo log file

file中存储的就是buffer中的block,buffer根据以下规则把block刷新进磁盘(file)
1.事务提交时
2.buffer中一半的空间被使用
3.log checkpoint时

log group里会有多个redo log file,但每个group里只有一个log file header。
log block追加在file的最后部分(前面有headder,checkpoint等),在同一组中,一个file写满了会接着写入下一个file。写入不一定是顺序的,因为file还保存其他信息(4个512字节,仅在第一个file里保存)

重做日志的格式
redo_log_type + space + page_no + redo log body

1.type:重做日志类型
2.space:表空间ID
3.page_no:页偏移量

LSN 日志序列号(log sequence number)
8字节,单调递增
表示含义包括:log写入日志的字节总量;checkpoint位置;页的版本
在每个页中都有LSN,表示该页最后刷新时LSN的大小

恢复
InnoDB在启动时不管数据库是否正常关闭,都会尝试恢复
checkpoint表示已经刷新到磁盘页上的LSN,所以恢复时从checkpoint开始的地方恢复

undo
回滚利用undo
redo放在重做日志文件中,而undo存放在数据库内部的特殊段 undo segment中,位于共享表空间
InnoDB的MVCC(行多版本)通过undo实现
undo log会伴随redo log产生

每个rollback segment回滚段包含1024个undo 段,每个段中申请 undo页
在undo log segment分配页并写入undo log过程中也需要写入redo。当事务提交时,InnoDB会 将 undo log 放入列表中,方便之后purge(清除)操作;判断undo log所在页是否可以重用,可以的话直接分配给下一个事务
事务提交时会将undo log放入链表;若undo页的使用空间小于3/4,就可以被重用

purge需要确保不被其他事务共享时才会清除

undo种类
1.insert undo log
因为insert操作堆其他事务不可见,所以这个undo log可以在事务提交后直接删除,不需要purge

2.update undo log
undo因为需要维护MVCC机制,所以不能提交时删除,要存入undo log 链表,等待purge线程进行删除

删除操作并不是直接删除,而是把他标记可以删除,然后等待purge线程删除它

一个页上允许多个事务的undo log存在,但不代表事务在全局中提交的顺序,但是后面的事务产生的undo log 总是在后面。
InnoDB还维护了一个history列表,根据事务提交的顺序,把undo log链接起来

purge
purge用于最终完成delete和update操作,因为InnoDB要维护MVCC机制,所以记录不能在提交时马上执行,因为其他事务可能在引用此行。若此行不被其他事务引用,purge就会将其删除
InnoDB通过在history list中找undo log,再从undo log中找undo log的模式避免了大量的随机读取操作,提高了purge的效率

group commit
一次fsync可以刷新确保多个事务日志写入文件
开启二进制文件后变复杂了,见收藏文章

事务控制语句
默认设置下事务是自动提交的,如果需要显式的开启一个任务需要使用begin / start transaction / set autocommit = 0;

关于 commit 和rollback
以commit 为例
commit / commit work 在功能上没什么区别,但 commit work 会根据 completion_type的值有不同
completion_type = 1 时表示 commit work 结束后是 chain ,就是变为链事务
completion_type = 2 时表示 commit work 结束后是 release,提交后会自动断开与服务器的连接

一些语句如DDL等会产生隐式的提交操作

事务隔离级别
1.read uncommitted(未提交读)不用
事务中的修改,即使没有提交,其他事务也可以看得到
会导致“脏读”、“幻读”和“不可重复读取”,InnoDB不常用

2.read committed(提交读)幻读,不可重复读
大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据
避免了“脏读取”,但不能避免“幻读”和“不可重复读取”。该级别适用于大多数系统。

3.repeatable read(重复读) 都可避免
SQL没有幻读保护,InnoDB用Next-Key Lock避免幻读
保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。
避免了“脏读取”和“不可重复读取”的情况,但不能避免“幻读”,但是带来了更多的性能损失。

4.serializable(串行化)开销大
高级别隔离,InnoDB会对每个select后自动加上Lock in share mode,为每个读取操作加一个共享锁
最严格的级别,事务串行执行,资源消耗最大;

隔离级别越低,事务请求的锁越少,保持锁的时间越短

分布式事务
分布式事务指:允许多个独立的事务资源参与到一个全局的事务中
使用分布式事务时要求隔离级别为serializable

XA事务允许各个数据库不同,要么全部提交要么都回滚
XA事务组成:一个或多个资源管理器;一个事务管理器;一个应用程序;
资源管理器(RM):访问事务资源的方法(数据库)
事务管理器(TM):协调各个事务,将资源管理器通信
应用程序(AP):定义事物的边界,全局事务中的操作

两段式提交方式:
第一阶段:所有节点开始准备,告诉事务管理器(TM)准备好提交了
第二阶段:事务管理器(TM)告诉资源管理器(RM)进行回滚或者提交,如果任何一个节点出问题,全部回滚

与本地事务不同的是,分布式需要多次准备工作,等所有的都同意了再进行提交或回滚

前面是外部的XA事务,内部XA事务存在于binlog和InnoDB之间

不好的事务习惯
1.在循环中提交事务
2.使用自动提交
3.使用自动回滚

长事务
执行时间较长的事务,可以通过转化为小批量事务进行处理,如果错误只需要回滚一部分

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值