Files
rikako-note/mysql/mysql文档/mysql_事务.md
2025-06-27 00:48:51 +08:00

112 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 事务
## 事务分类
事务通常可分为如下类型:
- 扁平事务(flat transaction)
- 带保存点的扁平事务(flat transaction with savepoints)
- 链事务(chained transaction)
- 嵌套事务(nested transaction)
- 分布式事务(distributed transaction)
### 扁平事务
扁平事务为最常用的事务,在扁平事务中,所有操作都处于统一层次,其由`begin work`开始,并由`commit work``rollback work`结束。
扁平事务的操作是原子的,要么都提交,要么都回滚。
### 带有保存点的扁平事务
对于带有保存点的扁平事务,`其支持在事务执行过程中回滚到同一事务中较早的一个状态`
在事务执行过程中,可能并不希望所有的操作都回滚,放弃所有操作的代价可能太大。通过`保存点`,可以记住事务当前的状态,在后续发生错误后,事务能够回到保存点当时的状态。
相较于扁平事务只能够全部回滚,带保存点的扁平事务能够回滚到保存点时的状态。
保存点可以通过`save work`来创建,使用示例如下所示
<img alt="" height="752" src="https://i-blog.csdnimg.cn/blog_migrate/2ef380492373bb8e4a6e529109baee3c.png" width="728">
### 链事务
可视为保存点事务的一个变种。在使用带保存点的事务时,如果系统发生崩溃,那么所有的保存点都会消失。`在后续重启进行恢复时,事务需要从开始处重新执行`,而不是从最近的一个保存点开始执行。
> 若事务在数据库未提交时发生崩溃那么在数据库再次重启执行recovery操作时会对未提交的事务进行回滚即使之前事务存在保存点也会全部回滚
链事务的思想是,当提交事务时,释放不必要的数据对象,将必要的上下文隐式传递给下一个要开始的事务。`提交事务和开始下一个事务操作必须为原子操作`,下一个事务必须徐要能看到上一个事务的结果,示例如下:
<img class="trans" src="https://images2015.cnblogs.com/blog/754297/201602/754297-20160204112125600-267403241.jpg">
和带保存点的扁平事务不同的是,带保存点的扁平事务能够回滚到任意正确的保存点,而链事务只能回滚当前事务。
且链事务和带保存点的扁平事务,对于锁的处理也不同:
- `链事务`对于每个事务commit后释放持有的锁
- `带保存点的扁平事务`:在整个事务提交前,不会释放持有的锁
### 嵌套事务
嵌套事务为一个层次结构框架,由顶层事务控制各个层次的事务。嵌套在顶层事务中的事务被称为`子事务`
<img src="https://pic2.zhimg.com/v2-01f00b04df29181143da399008b92055_r.jpg">
如下为Moss理论嵌套事务的定义
- 嵌套事务是由若干事务组成的一颗树,子树既可以是嵌套事务,又可以是扁平事务
- 处在叶子节点的事务是扁平事务
- 位于根节点的事务被称为顶层事务,其他事务被称为子事务,事务的`predecessor`被称为父事务,事务的下一层事务被称为子事务
- 子事务既可以提交又可以回滚,但是子事务的提交并不会立马生效,除非其父事务已经被提交。`任何子事务都在顶层事务提交后才真正提交`
- 树中任何一个事务的回滚会引其所有子事务都一起回滚
在Moss理论中实际工作被交由叶子节点来完成`只有叶子节点的事务才能够访问数据库,发送消息,获取其他类型的资源``高层事务仅仅负责逻辑控制,即负责何时调用相关子事务`
即使一个系统不支持嵌套事务,也可以通过保存点技术来模拟嵌套事务。
#### savepoint和嵌套事务区别
在使用保存点来模拟嵌套事务时,在锁持有方面和嵌套事务有差别。
- 嵌套事务:在使用嵌套事务时,不同子事务在数据库持有的锁不同
- 保存点:在通过保存点来模拟嵌套事务时,用户无法选择哪些锁被哪些子事务继承,无论有多少个保存点,所有的锁都可以得到访问
### 分布式事务
通常是在分布式环境运行的扁平事务,需要访问网络中的不同节点。
分布式事务同样需要满足ACID的特性要么都发生要么都不发生。
对于innodb存储引擎其支持扁平事务、带有保存点的扁平事务、链事务、分布式事务。`innodb并不原生支持嵌套事务单可以通过带保存点的事务来模拟串行的嵌套事务`
## 事务实现
对于事务的ACID特性其实现如下
- `I(隔离性)`:事务隔离性通过锁来实现
- `A(原子性), D(持久性)`事务的原子性和持久性可以通过redo log来实现
- `C(一致性)`:事务一致性通过undo log来实现
### redo
redo log重做日志用于实现事务的持久性其由两部分组成
- 内存中的重做日志缓冲redo log buffer
- 磁盘中的重做日志文件redo log file
#### redo log persists before transaction committed
innodb存储引擎支持事务其通过`force log at commit`机制实现事务的持久性,即当事务提交时,必须先将该事务的所有日志写入到磁盘的日志文件中进行持久化,直到该过程完成后事务才提交完成。
> 上述描述中`提交时将事务所有日志写入到磁盘的日志文件中`,这句话中`日志`代表`redo log 和 undo log`。
> - redo log用于保证事务持久性
> - undo log用于帮助事务回滚也用于mvcc功能
#### redo log和undo log比较
- redo log在mysql server运行时只会被顺序的写入server运行时并不会被读取
- undo log则不同在server运行时可能需要对事务进行回滚或执行mvcc操作此时可能需要对undo log文件进行`随机读写`
#### redo log和binlog的比较
binglog通常用于对数据库进行`point in time`形式的恢复从某个时间点起恢复数据以及主从复制但是binlog和redo log的差别如下
- binlog针对的是mysql数据库级别不止用于innodb还用于其他存储引擎
- redo log属于innodb存储引擎级别
- binlog实际记录的是对应sql语句属于逻辑日志
- redo log实际记录的格式则是物理格式具体为针对某个页面的物理修改
redo log和 bin log日志写入磁盘的时机也有所不同
- bin log`仅在事务提交后才进行一次写入`
- redo log`在事务执行过程中也可能发生写入`redo log buffer满后会写入到磁盘中故而redo log file中同一事务写入的redo log内容可能并非是连续的`多个事务在写入redo log时可能会交叉写入`
#### innodb_flush_log_at_trx_commit
参数`innodb_flush_log_at_trx_commit`用于控制redo log/ undo log刷新到磁盘的策略该参数默认值为`1`,即事务提交时刷新日志到磁盘。除了默认值之外,还可以为该参数设置如下值:
- 0 事务提交时不刷新日志到磁盘仅在master thread中刷新日志到磁盘master thread中刷新操作每秒触发一次
- 2事务提交时刷新日志但是仅将日志写入到文件系统的缓存中`并不进行fsync操作`
`innodb_flush_log_at_trx_commit`参数设置为`0``2`虽然可以在一定幅度上提高性能但是会丧失数据库的ACID特性。