mysq系列之事务

MySQL InnoDB 的事务机制是其最核心的特性之一,它通过严格遵循 ACID 模型,为数据提供了可靠的并发控制和故障恢复能力。下面从多个维度详细介绍 InnoDB 的事务。


1. 事务的定义

事务是一组原子性的 SQL 操作,要么全部执行成功,要么全部不执行。在 InnoDB 中,事务可以显式开启和结束,也可以隐式地通过自动提交模式管理。


2. ACID 属性与 InnoDB 的实现

属性 含义 InnoDB 实现方式
原子性 事务中的操作要么全部完成,要么全部回滚 通过 undo log 记录修改前的旧值,事务回滚时利用 undo log 恢复数据
一致性 事务前后数据库的完整性约束不被破坏 通过原子性、隔离性、持久性共同保证,同时外键约束、触发器、数据类型检查等也发挥作用
隔离性 多个事务并发执行时,相互隔离,不互相干扰 通过 MVCC(多版本并发控制)锁机制(行锁、间隙锁、Next-Key 锁)实现不同的隔离级别
持久性 事务一旦提交,其修改永久保存,即使系统崩溃也不丢失 通过 redo log 实现。提交时先写 redo log(WAL 技术),崩溃恢复时重放 redo log 确保已提交事务的修改不丢失

3. 事务控制语句

sql

sql 复制代码
-- 显式开启事务
START TRANSACTION;   -- 或 BEGIN;

-- 提交事务(永久生效)
COMMIT;

-- 回滚事务(撤销当前事务所有修改)
ROLLBACK;

-- 设置保存点,实现部分回滚
SAVEPOINT sp1;
ROLLBACK TO SAVEPOINT sp1;
RELEASE SAVEPOINT sp1;

-- 设置自动提交模式(默认开启,每条语句自动提交)
SET autocommit = 0;   -- 关闭自动提交,需手动 COMMIT
SET autocommit = 1;   -- 开启自动提交

4. 事务隔离级别

InnoDB 支持 SQL 标准定义的四种隔离级别,默认使用 REPEATABLE READ

隔离级别 脏读 不可重复读 幻读 说明
READ UNCOMMITTED 可能 可能 可能 读未提交,最低隔离,一般不使用
READ COMMITTED 不可能 可能 可能 Oracle 默认级别,只读已提交数据
REPEATABLE READ 不可能 不可能 可能(InnoDB 通过 MVCC + 间隙锁解决) InnoDB 默认级别,可重复读,避免幻读
SERIALIZABLE 不可能 不可能 不可能 强制事务串行执行,读加锁,性能最低
  • 脏读:读到其他事务未提交的数据。
  • 不可重复读:同一事务内两次读同一行数据,结果不一致(因其他事务修改并提交)。
  • 幻读:同一事务内两次执行相同查询,结果集行数不一致(因其他事务插入或删除)。

设置隔离级别

sql

sql 复制代码
-- 查看当前隔离级别
SELECT @@transaction_isolation;

-- 设置会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

5. MVCC(多版本并发控制)

InnoDB 通过 MVCC 实现高并发下的非锁定读,使得读操作不阻塞写操作,写操作也不阻塞读操作。

  • 实现原理 :每行记录隐藏两个列:DB_TRX_ID(最近修改的事务 ID)和 DB_ROLL_PTR(指向 undo log 中旧版本记录的指针)。
  • Read View:事务执行查询时,根据当前系统的活跃事务列表创建一个 Read View,决定哪些版本的数据可见。
  • 在 REPEATABLE READ 下:事务首次读取时创建 Read View,直到事务结束都复用该视图,从而保证可重复读。
  • 在 READ COMMITTED 下:每条语句执行时都重新创建 Read View,因此每次读取可能看到最新的已提交数据。

MVCC 配合 undo log 使得 InnoDB 在大多数读场景下不需要加锁,显著提升并发性能。


6. 锁机制

InnoDB 使用多种锁来保证事务隔离性,锁粒度以行级为主,兼顾表级。

6.1 锁类型

  • 共享锁(S锁) :允许事务读一行,阻止其他事务加排他锁。
    SELECT ... LOCK IN SHARE MODE;
  • 排他锁(X锁) :允许事务读/写一行,阻止其他事务加任何锁。
    SELECT ... FOR UPDATE; 或 DML 语句自动加 X 锁。

6.2 行锁算法

  • Record Lock:锁定单条记录。
  • Gap Lock:锁定索引记录之间的间隙(范围),防止幻读。
  • Next-Key Lock:Record Lock + Gap Lock 的组合,InnoDB 在 REPEATABLE READ 级别下默认使用,锁定一个范围并包含记录本身,有效防止幻读。

6.3 意向锁

表级锁,用于协调行锁和表锁。当加行锁时,InnoDB 自动给表加意向锁,避免其他事务对整个表加锁时遍历所有行。


7. 并发问题与隔离级别的解决

并发问题 定义 解决方案
脏读 读到未提交的数据 隔离级别 ≥ READ COMMITTED 时,通过 MVCC 只读已提交版本
不可重复读 同一事务内两次读同一行结果不同 隔离级别 ≥ REPEATABLE READ 时,通过 MVCC 的 Read View 复用解决
幻读 同一事务内两次查询结果集行数不同 REPEATABLE READ 下,InnoDB 使用 Next-Key Lock 锁定范围,防止新数据插入;SERIALIZABLE 下通过表级锁避免

8. 事务的自动提交与隐式提交

  • 自动提交模式 :默认每个 SQL 语句作为一个事务自动提交。可通过 SET autocommit=0 关闭,此时需要显式 COMMIT。
  • 隐式提交 :某些语句(如 DDL 语句 CREATE TABLEALTER TABLETRUNCATE 等)会隐式提交当前事务。

9. 总结

InnoDB 的事务机制通过 undo log 保证原子性和 MVCC,redo log 保证持久性,锁 + MVCC 实现隔离性,从而完整支持 ACID。默认隔离级别 REPEATABLE READ 结合 Next-Key Lock 能有效避免幻读,同时保持较高的并发性能。在实际开发中,合理控制事务大小、隔离级别和锁粒度,是保障数据库性能和一致性的关键。

相关推荐
知识分享小能手2 小时前
Redis入门学习教程,从入门到精通,Redis进阶编程知识点详解(5)
数据库·redis·学习
MekoLi292 小时前
MongoDB 新手完全指南:从入门到精通的实战手册
数据库·后端
cyforkk2 小时前
Spring AOP 进阶:揭秘 @annotation 参数绑定的底层逻辑
java·数据库·spring
2401_884970612 小时前
用Pygame开发你的第一个小游戏
jvm·数据库·python
麦聪聊数据2 小时前
快速将Oracle数据库发布为 API:使用 QuickAPI 实现 SQL2API
数据库·sql·低代码·oracle·restful
6+h2 小时前
【Redis】数据结构讲解
数据结构·数据库·redis
ID_180079054732 小时前
小红书笔记详情 API 接口系列 + 标准 JSON 返回参考(完整版)
数据库·笔记·json
wertyuytrewm2 小时前
用Python实现自动化的Web测试(Selenium)
jvm·数据库·python
我真会写代码2 小时前
Java事务核心原理与实战避坑指南
java·开发语言·数据库