当前位置: 首页 > news >正文

4.2.3 MYSQL事务原理分析

文章目录

  • 4.2.3 MYSQL事务原理分析
    • 1. 事务
      • 1. 前提:并发连接访问
      • 2. 事务定义
      • 3. 事务语句:
      • 4. acid特性
      • 5. undolog-回滚日志
      • 6. redolog-重做日志
    • 2. 隔离级别
      • 1. 四种隔离级别
      • 2. 并发问题解释
      • 3. 隔离级别设置
    • 3. MVCC(Multiversion Concurrency Control,多版本并发控制)(重点)
      • 1. read view
      • 2. 不同隔离级别下MVCC行为
      • 3. 快照读 VS 当前读
      • 4. redo/undo
    • 4. 锁
      • 1. 锁的粒度
      • 2. 锁类型
        • 1. 全局锁
        • 2. 表级锁
        • 3. 行级锁
      • 3. 锁的算法
    • 5. 死锁
      • 1. 相反加锁顺序死锁
      • 2. 锁冲突死锁
      • 3. 查看死锁
      • 3. 如何避免死锁

4.2.3 MYSQL事务原理分析

1. 事务

1. 前提:并发连接访问

在数据库中,多个连接同时访问(并发),容易引发数据混乱,需要事务来保证操作的完整性和正确性

2. 事务定义

是用户定义一系列操作,这些操作要不然都做,要不然都不做,不可分割,告诉mysql这是不可分割的一系列整体

3. 事务语句:

-- 显示开启事务
START TRANSACTION 
-- 提交事务,并使得已对数据库做的所有修改持久化
COMMIT
-- 回滚事务,结束用户的事务,并撤销正在进行的所有未提交的修改
ROLLBACK
-- 创建一个保存点,一个事务可以有多个保存点
SAVEPOINT identifier
-- 删除一个保存点
RELEASE SAVEPOINT identifier
-- 事务回滚到保存点
ROLLBACK TO [SAVEPOINT] identifier

4. acid特性

特性解释备注
A - Atomicity(原子性)事务中的操作要么全部成功,要么全部失败通过 undo log 支持回滚
C - Consistency(一致性)事务执行前后,数据保持一致依靠约束、外键等规则
I - Isolation(隔离性)多个事务之间互不干扰MVCC支持非锁定一致性读
D - Durability(持久性)提交后的数据永久保存,即使系统宕机依靠 redo log

5. undolog-回滚日志

  1. 用于回滚数据
  2. 当事务执行过程中出现错误或被用户取消,undo log 记录修改前的旧值,可以通过它恢复原状
  3. 存在于 InnoDB 引擎中

6. redolog-重做日志

  1. 用于恢复数据
  2. 事务提交前,会先把修改写入 redo log,防止崩溃丢失
  3. 提交时再持久化到磁盘数据页,确保事务的持久性(D)
  4. InnoDB 特有,保证即使宕机也能恢复到提交状态

2. 隔离级别

  1. 并发访问时,如果没有控制好,事务之间互相干扰,可能会产生各种脏读、不可重复读、幻读等问题。
  2. 隔离级别就是用来平衡:并发性能 vs. 数据正确性(隔离得越严格,性能越低,但数据越安全)

1. 四种隔离级别

隔离级别描述可能出现的问题
READ UNCOMMITTED(读未提交)可以读到别的事务未提交的数据脏读、不可重复读、幻读
READ COMMITTED(读已提交)只能读到别的事务已提交的数据不可重复读、幻读
REPEATABLE READ(可重复读)(MySQL默认)同一事务中,多次读取同一数据结果一致幻读(MySQL用Gap锁避免了)
SERIALIZABLE(可串行化)强制事务串行执行,完全隔离无任何并发问题,但性能最低

2. 并发问题解释

  1. 脏读:读到了未提交事务修改的数据。
  2. 不可重复读:同一事务中两次读到的数据不一样(因为别的事务提交了修改)。
  3. 幻读:同一事务中,查询时发现新增了数据行

3. 隔离级别设置

-- 查看当前隔离级别
SELECT @@tx_isolation;--临时修改当前会话隔离级别(只影响当前连接)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;--修改全局隔离级别(需要重启或新连接生效)
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

3. MVCC(Multiversion Concurrency Control,多版本并发控制)(重点)

  1. 提高并发性能,保证读一致性(不加锁也能读到合理数据)。用来实现一致性的非锁定读;非锁定读是指不需要等待访问的行上X锁的释放

  2. 原理:对每条记录保存多个版本(通过undo log),不同事务读取时根据自己的Read View判断可见性

1. read view

项目作用
m_ids当前活跃的事务ID集合(还未提交的事务)
min_trx_id当前活跃事务中最小的事务ID
max_trx_id下一个即将分配的事务ID
creat_trx_id每一行数据的创建事务ID(trx_id字段)
  1. trx_id < min_trx_id ;说明该记录在创建 read_view 之前已经提交,所以对当前事务可见;
  2. trx_id >= max_trx_id ;说明该记录是在创建 read_view 之后启动事务生成的,所以对当前事务
    不可见;
  3. min_trx_id <= trx_id < max_trx_id ;此时需要判断是否在 m_ids 列表中;
    • 在列表中;生成该版本记录的事务仍处于活跃状态,该版本记录对当前事务不可见;
    • 不在列表中;生成该版本记录的事务已经提交,该版本记录对当前事务可见;

2. 不同隔离级别下MVCC行为

在 read committed 和 read repeatable 隔离级别下,MVCC 采用 read view 来实现的,它们的区别在于创建 read view 时机不同

隔离级别MVCC处理说明
READ COMMITTED(读已提交)每次查询都生成新的 Read View读到别人刚提交的数据(变化的快照)
REPEATABLE READ(可重复读)整个事务期间共用同一个 Read View保证事务内读到的数据不变

3. 快照读 VS 当前读

类型说明举例
快照读(Snapshot Read)非锁定读,走MVCC快照SELECT * FROM table WHERE id = 1;
当前读(Current Read)加锁读,拿最新版本SELECT * FROM table WHERE id = 1 FOR UPDATE;

4. redo/undo

日志作用何时使用
Redo Log用来恢复已提交事务的修改(崩溃恢复)crash后根据redo log恢复
Undo Log保存数据的旧版本,供回滚或MVCC快照读使用回滚或快照读时用

undo log 会随着事务提交后被清理掉(并不是永久保存)

4. 锁

在 MySQL 中,锁是并发控制的核心机制,主要包括不同粒度的锁(行、页、表)和不同类型的锁(共享锁、排他锁、意向锁等)。

1. 锁的粒度

MySQL 中事务使用的是粒度锁(Granular Locking),主要体现在以下三个层次:

  1. 表级锁(Table-Level Lock):作用于整张表,开销小,加锁快,但并发性低。
  2. 页级锁(Page-Level Lock):作用于数据页(主要用于 MyISAM 的索引缓存,InnoDB 不使用)。
    3。 行级锁(Row-Level Lock):作用于某一行记录,开销大,加锁慢,但并发性好,InnoDB 支持。

2. 锁类型

1. 全局锁
  1. 全局只读锁:使用 FLUSH TABLES WITH READ LOCK,可用于做一致性备份,防止其他事务对数据进行修改。
  2. 全局写锁:使用 LOCK TABLES,可用于做表结构变更。
    注意:
  • 全局锁会锁定整个数据库,其他事务无法进行读写操作。
2. 表级锁
  1. 意向共享锁(IS Lock):事务打算对表中某些记录加共享锁
  2. 意向排他锁(IX Lock):事务打算对表中某些记录加排他锁
    意向锁不会阻塞其他意向锁,但会与表级的共享或排他锁发生冲突
3. 行级锁
  1. 共享锁(S Lock):又称读锁,允许其他事务也获得该行的共享锁(读读并发)
  2. 排他锁(X Lock):又称写锁,阻止其他事务获得该行的任何锁(独占写)
    InnoDB 使用MVCC + 行锁结合实现高并发控制

3. 锁的算法

InnoDB 使用多种行锁算法来保证事务隔离性

  1. 记录锁(Record Lock)
    定义:锁定索引上的某一行记录。
    作用:防止其他事务对该记录进行修改或删除。
    示例:
SELECT * FROM user WHERE id = 5 FOR UPDATE;

若 id 有索引,这条语句会对 id=5 的那一条记录加记录锁

  1. 间隙锁(Gap Lock)
    定义:锁定某一范围之间的间隙,不锁定已有记录。
    作用:防止其他事务在该范围内插入新记录,避免“幻读”。
    特点:仅适用于 范围查询,例如 <, >, BETWEEN。
    示例:
SELECT * FROM user WHERE id < 5 FOR UPDATE;

会锁住 (5, ∞) 范围的间隙,阻止插入 id > 5 的新记录。

  1. 临键锁(Next-Key Lock)
    定义:记录锁 + 前一个间隙锁的组合。
    作用:锁定某一条记录及其前面的间隙。
    目的:在可重复读(RR)隔离级别下防止幻读。
    示例:
SELECT * FROM user WHERE id BETWEEN 5 AND 10 FOR UPDATE;

会加多个临键锁,如:
(4, 5],锁住 id=5
(5, 6],锁住 id=6

(9, 10],锁住 id=10

5. 死锁

死锁是指两个或多个事务在执行过程中因争夺资源而互相等待,导致程序无法继续执行下去的现象。在 InnoDB 中,死锁一旦被检测到,会自动回滚其中一个事务来解除死锁

1. 相反加锁顺序死锁

两个事务以不同顺序获取相同资源,互相等待对方释放。

示例:


-- 事务A
LOCK row 1;
LOCK row 2;-- 事务B
LOCK row 2;
LOCK row 1;  -- 等待A释放,造成死锁

2. 锁冲突死锁

一个事务未能及时释放锁,另一个事务等待同一资源,导致互相阻塞。常见于高并发写操作 + 高隔离级别(如可重复读)

解决建议

  1. 降低隔离级别至 Read Committed,避免不必要的间隙锁。
  2. 减小锁粒度,避免大范围更新或范围查询

3. 查看死锁

SHOW ENGINE INNODB STATUS;  -- 查看死锁信息SELECT * FROM information_schema.INNODB_LOCKS;-- 查看当前锁信息
SELECT * FROM information_schema.INNODB_LOCK_WAITS;

3. 如何避免死锁

方法说明
统一加锁顺序所有事务访问资源时使用一致的顺序加锁,避免环形等待
控制事务粒度与范围缩小每个事务锁定的数据范围和执行时间
减少范围查询减少 BETWEEN / < / > 查询,避免间隙锁干扰
合理设置索引避免全表扫描导致不必要的行锁或表锁
设置死锁重试机制(代码层)捕获错误码 1213,程序自动重试一次事务操作
适当降低隔离级别如使用 Read Committed 替代 Repeatable Read

相关文章:

  • ESM模块加载机制全景解析
  • docker部署的Nextcloud,处于维护模式,如何解决
  • 程序员如何用AI工具实现“快速验证原型”
  • Linux环境变量以及进程虚拟地址原理
  • 共享货源系统,多商户独立站助力行业资源整合
  • [逆向工程]什么是CPU寄存器(三)
  • JavaScript原型,原型链 ? 有什么特点?
  • 第33周JavaSpringCloud微服务 多人协作下的调试
  • Docker与Vmware网络模式的对别
  • MongoDB的下载安装与启动
  • Laravel+API 接口
  • 爬虫学习笔记(五)---数据解析之re
  • MyBatis、MyBatis-Plus、Hibernate、Spring Data JPA 等 Java 持久层技术的理解和对比
  • 【学习笔记】计算机操作系统(二)—— 进程的描述与控制
  • 源码编译安装LAMP
  • 空间权重矩阵
  • 阿里云服务器 篇十三:Web书签(链接共享和迷你导航)
  • 强化学习贝尔曼方程推导
  • MCP协议的起源与发展历史:从基础通信到现代分布式系统的支撑者
  • Spring Boot 集成 ActiveMQ 实现异步消息通信(一)
  • 国铁集团郑州局预计“五一”发送642.5万人
  • 巴西外长维埃拉:国际形势日益复杂,金砖国家必须发挥核心作用
  • 建发股份:将于5月6日召开股东大会,审议提名林茂等为公司新一届董事等议案
  • 美加征“对等关税”后,调研显示近半外贸企业将减少对美业务
  • 劳动最光荣!2426人受到表彰
  • 暴涨96%!一季度“中国游中国购”持续升温,还有更多利好