事务机制
2026/1/15大约 3 分钟
事务机制
什么是事务
事务是一组操作的集合,要么全部成功,要么全部失败。
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;ACID 特性
| 特性 | 说明 | 实现方式 |
|---|---|---|
| 原子性(Atomicity) | 事务不可分割 | undo log |
| 一致性(Consistency) | 数据状态一致 | 其他三个特性保证 |
| 隔离性(Isolation) | 事务互不干扰 | 锁 + MVCC |
| 持久性(Durability) | 提交后永久保存 | redo log |
事务隔离级别
并发问题
| 问题 | 说明 |
|---|---|
| 脏读 | 读到其他事务未提交的数据 |
| 不可重复读 | 同一事务内两次读取结果不同(数据被修改) |
| 幻读 | 同一事务内两次读取结果不同(数据被插入/删除) |
隔离级别
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | ✓ | ✓ | ✓ |
| READ COMMITTED | ✗ | ✓ | ✓ |
| REPEATABLE READ | ✗ | ✗ | ✓ |
| SERIALIZABLE | ✗ | ✗ | ✗ |
提示
MySQL 默认隔离级别是 REPEATABLE READ,并通过 MVCC + 间隙锁解决了幻读问题。
设置隔离级别
-- 查看当前隔离级别
SELECT @@transaction_isolation;
-- 设置隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;MVCC 多版本并发控制
核心概念
- 隐藏列:每行数据包含
trx_id(事务ID)和roll_pointer(回滚指针) - undo log:记录数据的历史版本
- Read View:事务的可见性视图
版本链
Read View
Read View 包含四个字段:
| 字段 | 说明 |
|---|---|
| m_ids | 活跃事务 ID 列表 |
| min_trx_id | 最小活跃事务 ID |
| max_trx_id | 下一个要分配的事务 ID |
| creator_trx_id | 创建 Read View 的事务 ID |
可见性判断
RC vs RR 的区别
| 隔离级别 | Read View 创建时机 |
|---|---|
| READ COMMITTED | 每次 SELECT 创建新的 |
| REPEATABLE READ | 第一次 SELECT 创建,后续复用 |
undo log
作用
- 事务回滚:保存数据修改前的值
- MVCC:提供数据的历史版本
类型
| 类型 | 说明 |
|---|---|
| insert undo log | INSERT 操作产生,事务提交后删除 |
| update undo log | UPDATE/DELETE 操作产生,需要保留给 MVCC |
回滚过程
-- 原始数据:id=1, name='张三'
UPDATE users SET name = '李四' WHERE id = 1;
-- undo log 记录:id=1, name='张三'
-- 回滚时:根据 undo log 恢复数据redo log
作用
保证事务的持久性,即使系统崩溃也能恢复数据。
WAL(Write-Ahead Logging)
先写日志,再写磁盘。
刷盘策略
-- innodb_flush_log_at_trx_commit
-- 0:每秒刷盘
-- 1:每次提交刷盘(默认,最安全)
-- 2:每次提交写入 OS 缓存,每秒刷盘| 值 | 性能 | 安全性 |
|---|---|---|
| 0 | 最高 | 最低 |
| 1 | 最低 | 最高 |
| 2 | 中等 | 中等 |
binlog
作用
- 主从复制
- 数据恢复
与 redo log 的区别
| 特性 | redo log | binlog |
|---|---|---|
| 层级 | InnoDB 引擎 | Server 层 |
| 内容 | 物理日志(页的修改) | 逻辑日志(SQL 语句) |
| 写入方式 | 循环写 | 追加写 |
| 用途 | 崩溃恢复 | 主从复制、数据恢复 |
两阶段提交
保证 redo log 和 binlog 的一致性。
事务操作
-- 开启事务
START TRANSACTION;
-- 或
BEGIN;
-- 提交事务
COMMIT;
-- 回滚事务
ROLLBACK;
-- 设置保存点
SAVEPOINT sp1;
ROLLBACK TO sp1;
-- 自动提交
SET autocommit = 0; -- 关闭
SET autocommit = 1; -- 开启(默认)长事务的危害
- 占用锁资源,阻塞其他事务
- undo log 无法回收,占用空间
- 主从延迟
避免长事务
-- 查看长事务
SELECT * FROM information_schema.innodb_trx
WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60;
-- 设置事务超时
SET innodb_lock_wait_timeout = 50;