数据库学习(六)——MySQL事务
一、MySQL事务
MySQL 中的 事务(Transaction) 是一种将多个 SQL 操作打包成一个整体执行的机制,确保数据的一致性和可靠性。事务广泛用于需要原子性的数据操作,比如转账、订单创建等。
事务的四大特性(ACID):
特性 | 说明 |
---|---|
原子性(Atomicity) | 一个事务中的操作要么全部成功,要么全部失败,不可分割。 |
一致性(Consistency) | 事务执行前后,数据库处于一致状态(遵守约束规则、业务规则)。 |
隔离性(Isolation) | 多个事务互不干扰,彼此隔离。事务并发时数据仍一致。 |
持久性(Durability) | 一旦事务提交,修改永久保存,即使系统崩溃也不会丢失。 |
二、事务基本语句
事务基本语句(InnoDB 引擎支持事务):
语句 | 作用 |
---|---|
START TRANSACTION; 或 BEGIN; | 显式开始一个事务 |
COMMIT; | 提交事务,永久保存所有操作 |
ROLLBACK; | 回滚事务,撤销所有操作 |
SAVEPOINT 保存点名; | 设置一个保存点,用于部分回滚 |
ROLLBACK TO 保存点名; | 回滚到某个保存点,仅撤销一部分操作 |
SET autocommit = 0; | 关闭自动提交,进入手动事务控制状态 |
SET autocommit = 1; | 恢复自动提交(默认) |
注意:
MySQL 默认是自动提交模式,即每条语句自动提交。
示例一:基本事务流程
START TRANSACTION;UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;COMMIT;
如中途出错,也可用:
ROLLBACK;
示例二:使用保存点(SAVEPOINT
)
START TRANSACTION;UPDATE users SET score = score + 10 WHERE id = 1;SAVEPOINT sp1;UPDATE users SET score = score - 50 WHERE id = 2;ROLLBACK TO sp1;COMMIT;
注意:
- 第二条
UPDATE
被撤销,第一条仍然生效。
三、事务隔离级别(Isolation Level)
事务隔离级别定义了一个事务能看到其他事务对数据库的更改程度。
级别 | 可解决的问题 | 会出现的问题 | MySQL默认 |
---|---|---|---|
READ UNCOMMITTED | 无 | 会出现脏读 | ❌ |
READ COMMITTED | 解决脏读 | 可能出现不可重复读 | ❌ |
REPEATABLE READ (默认) | 解决脏读和不可重复读 | 可能出现幻读 | ✅ |
SERIALIZABLE | 解决所有问题(脏读、不可重复读、幻读) | 并发性能差 | ❌ |
设置事务隔离级别:
SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL REPEATABLE READ;
四、事务中的日志机制
日志类型 | 作用 |
---|---|
Undo Log | 撤销未提交的事务、实现 MVCC |
Redo Log | 保证事务提交后数据的持久性 |
Binlog | 用于主从复制、增量备份 |
InnoDB 使用 “先写日志、后写磁盘” 策略,避免崩溃丢数据。
五、事务引擎:InnoDB
MySQL 中支持事务的主要引擎是 InnoDB,它是 MySQL 的默认存储引擎,也是最常用于高可靠性、高并发场景的引擎。
1. InnoDB 引擎简介
特性 | 是否支持 | 说明 |
---|---|---|
支持事务(ACID) | ✅ | 完整支持事务四大特性 |
行级锁定 | ✅ | 并发控制粒度细,避免表级锁带来的性能问题 |
外键约束 | ✅ | 支持 FOREIGN KEY 语法进行引用完整性约束 |
自动崩溃恢复 | ✅ | 通过 Redo Log (重做日志) 和 Undo Log (回滚日志) 实现 |
多版本并发控制(MVCC) | ✅ | 实现高并发下的非阻塞读操作 |
支持全文索引 | ✅(5.6+) | 支持 FULLTEXT 索引,适用于文本搜索 |
表空间管理 | ✅ | 支持独立表空间 (innodb_file_per_table ) |
2. InnoDB 事务核心机制
InnoDB 通过以下几项核心机制实现高可靠事务性:
(1) Undo Log
(回滚日志)
- 在数据修改前记录一份旧值(用于回滚或 MVCC)。
- 保证事务回滚和一致性视图。
- 存储在
undo segment
中,自动清理。
(2)Redo Log
(重做日志)
- 记录已提交事务对数据的修改操作。
- 用于 崩溃恢复,防止宕机后数据丢失。
- 先写日志再写磁盘(WAL:Write-Ahead Logging)。
- 由
ib_logfile0/1
或#innodb_redo
文件组成。
(3)MVCC
(多版本并发控制)
- 实现
快照读
,避免加锁,提高读性能。 - 每条记录有隐藏的事务ID和回滚指针。
- 只有
REPEATABLE READ
和READ COMMITTED
使用 MVCC。
3. 事务隔离级别(Isolation Level)
InnoDB 支持 SQL 标准的 4 种隔离级别:
隔离级别 | 是否支持脏读 | 是否支持不可重复读 | 是否支持幻读 | InnoDB 默认 |
---|---|---|---|---|
READ UNCOMMITTED | ✅ | ✅ | ✅ | 否 |
READ COMMITTED | ❌ | ✅ | ✅ | 否 |
REPEATABLE READ | ❌ | ❌ | ✅ | ✅ 默认 |
SERIALIZABLE | ❌ | ❌ | ❌ | 否 |
💡 InnoDB 通过 间隙锁(Gap Lock) 解决幻读,而不是真正序列化。
六、事务并发问题
并发问题 | 描述 | 影响隔离级别 |
---|---|---|
脏读 | 读到未提交事务的数据 | 仅 SERIALIZABLE & REPEATABLE READ 避免 |
不可重复读 | 两次查询同一记录,结果不同(别的事务修改了数据) | REPEATABLE READ 能避免 |
幻读 | 两次查询满足条件的记录数不同(别的事务插入了新数据) | SERIALIZABLE 避免 |
七、典型示例——银行转账事务
START TRANSACTION;UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;-- 出错则回滚
-- IF (error) THEN
-- ROLLBACK;
-- ELSE
COMMIT;
注意:
- 如果两个
UPDATE
都成功执行,则COMMIT
,数据写入磁盘; - 如果任一语句执行失败(例如账户不存在、余额不足等),应手动调用
ROLLBACK
撤销所有操作。
八、两阶段提交(事务+Binlog
)
InnoDB 为保证与 Binlog
一致,使用两阶段提交机制(prepare → commit):
- 写
Redo Log
prepare; - 写
Binlog
; Redo Log
commit;
保证主从一致性,避免部分提交。
九、MySQL事务常见问题与答案
问题 | 简要答案 |
---|---|
InnoDB 如何保证事务原子性? | Undo Log 记录原始版本,失败时可回滚 |
如何防止脏读? | 设置隔离级别为 READ COMMITTED 或更高 |
什么是幻读?怎么解决? | 并发插入导致结果数量变化,使用 Gap Lock / SERIALIZABLE 隔离级别 |
Redo Log 和 Binlog 有何不同? | Redo 是物理日志用于崩溃恢复;Binlog 是逻辑日志用于复制与备份 |