萤火小屋

萤火小屋分享世界

  • 首页
  • 归档
  • 分类
  • 标签
  • 留言
  • 关于

  • 搜索
分治算法 归并排序 快排 手撕 事务 MySQL索引 MySQL 小技巧 Spring Framework Spring 动态规划 Linux Android 贪心算法 操作系统 进程调度模拟 IPv6 数据库 计算机组成原理 计算机基础 栈 Java 静态路由 路由器 交换机 数字通信 网络工程 计算机网络 Web http 大学学习技巧 程序设计 算法

MySQL-InnoDB引擎的事务

发表于 2021-03-18 | 分类于 MySQL | 0 | 阅读次数 23

1 一致性(consistency)

1.1 undo log的机制

  1. undo log存放在数据库内部的一个特殊段(segment)中,这个段称为undo段(undosegment)。
  2. undo log是逻辑日志,因此只是将数据库逻辑地恢复到原来的样子。
  3. undo log的另一个作用是MVCC,即在InnoDB存储引擎中MVCC的实现是通过undo来完成。
  4. undo log的产生会伴随着redo log的产生,这是因为undo log也需要持久性的保护。

1.2 undo log与redo log的区别

  1. redo log通常是物理日志,记录的是页的物理修改操作。
  2. undo log是逻辑日志,根据每行记录进行记录。

2 隔离性(Isolation)

  • 为了性能往往不能100%兼顾隔离性。

2.1 通过lock(锁)实现

2.1.1 粒度

  1. 行锁
  2. 表锁

2.1.2 类型

  1. 共享锁(S):与IX/X锁不兼容
    行锁,允许事务读一行数据
  2. 排他锁(X):与任何锁都不兼容
    行锁,允许事务删除或更新一行数据
  3. 意向共享锁(IS):与X锁不兼容
    表锁,事务想要获得一张表中某几行的共享锁
  4. 意向排他锁(IX):与S/X锁不兼容
    表锁,事务想要获得一张表中某几行的排他锁

总结:

  1. X锁与任何锁都不兼容
  2. IX锁与S/X锁不兼容

2.1.3 机制

  1. 无锁
    MVCC(Multi-Version Concurrency Control):对于正在更新的数据,InnoDB会去读取该行的一个快照数据(undo log)

  2. 加锁
    X锁:SELECT ... FOR UPDATE
    S锁:SELECT ... LOCK IN SHARE MODE

2.1.4 算法

  1. Record Lock:单个行记录上的锁,总是会去锁住(聚簇/主键)索引记录
  2. Gap Lock:间隙锁,锁定一个范围,但不包含记录本身
  3. Next-Key Lock:锁定一个范围,并且锁定记录本身

2.1.5 问题

2.1.5.1 读取

  1. 脏读:某一个事务,读取了另外一个事务中未提交的数据(绝对要避免)

image.png

  1. 不可重复读:某一个事务,对同一个数据前后读取的结果不一致(有时也可以接受,但是要尽力杜绝)

image.png

  1. 幻读:某一个事务,对同一个表前后查询到的行数不一致(往往可以接受,但是尽量避免)

image.png

2.1.5.2 更新

  1. 第一类丢失更新:某一个事务的回滚,导致另外一个事务已更新的数据丢失了

image.png

  1. 第二类丢失更新:某一个事务的提交,导致另外一个事务已更新的数据丢失了

image.png

说明:任何隔离级别都不会发生这类问题,因为对于DML操作需要先加IX锁,它会直接阻塞事务2的行为。

2.1.6 死锁

2.1.6.1 场景

事务1:
update ... where id=1;
update ... where id=2;​

事务2:
update ... where id=2;
update ... where id=1;

2.1.6.2 解决

  1. 超时回滚(被动):innodb_lock_wait_timeout,当一个等待时间超过设置的某一阈值时,其中一个事务进行回滚,另一个等待的事务就能继续进行。
  2. 死锁检测(主动):wait-for graph,采用等待图的方式来进行死锁检测,这是一种更为主动的死锁检测方式。

image.png

2.1.7 升级

InnoDB存储引擎不存在锁升级的问题。
因为其不是根据每个记录来产生行锁的,相反,其根据每个事务访问的每个页对锁进行管理的,采用的是位图的方式。因此不管一个事务锁住页中一个记录还是多个记录,其开销通常都是一致的。

2.2 隔离级别

2.2.1 READ UNCOMMITTED

  • 未解决脏读、不可重复读、幻读问题

2.2.2 READ COMMITTED

  1. 采用Record Lock算法,解决了脏读问题
  2. 采用MVCC,总是读取被锁定行的最新一份快照数据

2.2.3 REPEATABLE READ

  1. 是默认的隔离级别;
  2. 采用Next-Key Lock算法,解决了脏读、不可重复读、幻读问题
  3. 采用MVCC,总是读取事务开始时的行数据版本

2.2.4 SERIALIZABLE

  • 解决了脏读、不可重复读、幻读问题(SELECT ... LOCK IN SHARE MODE)

3 持久性(Durability)

使用redo log来解决

3.1 redo log的机制

  1. 当事务提交时,必须先将该事务的所有日志写入到redo log进行持久化,待事务的COMMIT操作完成才算完成。
  2. redo log是顺序写的,在数据库运行时不需要对该文件进行读取操作。
  3. 每次写入redo log文件后,InnoDB引擎都需要调用一次fsync操作。
  4. redo log通常是物理日志,记录的是页的物理修改操作。

3.2 redo log与bin log的区别

  1. redo log是在存储引擎层产生,bin log是在数据库的上层产生的,并且bin log​不仅仅针对于InnoDB存储引擎,MySQL中任何存储引擎对于数据库的更改都会产生二进制日志。
  2. bin log 是一种逻辑日志,其记录的是对应的SQL语句,而InnoDB存储引擎层面的redo log​是物理格式日志,其记录的是对于每个页的修改。
  3. bin log只在事务提交完成后进行一次写入,而redo log​在事务进行中不断地被写入,这表现为日志并不是随事务提交的顺序进行写入的。

4 原子性(Atom)

一致性、隔离性和持久性的实现是原子性的保证。



文章脑图
# 数据库 # MySQL # 事务
MySQL数据库的索引
手撕快速排序-Java代码
  • 文章目录
  • 站点概览
优律

优律

萤火小屋分享世界

34 日志
13 分类
33 标签
E-mail Twitter Instagram
Links
  • CZLisyx - 浮生志
  • Vedfolnir
  • 崔笑颜的博客
  • 大耗子的小屋
0%
© 2019 — 2021 萤火小屋——优律的博客网站
网站已勉强运行 
Halo博客系统技术支持