MySQL事务与隔离级别深度解析
一、 事务基础概念
1. 什么是事务
事务(Transaction)是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作。事务具有以下四个关键特性(ACID):
原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成
一致性(Consistency):事务执行前后,数据库从一个一致状态变到另一个一致状态
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务
持久性(Durability):事务一旦提交,其结果就是永久性的
2. MySQL中的事务控制语句
START TRANSACTION; -- 或 BEGIN
-- 执行SQL操作
COMMIT; -- 提交事务
ROLLBACK; -- 回滚事务
二、事务隔离级别详解
1. 四种标准隔离级别
MySQL支持四种事务隔离级别,控制不同事务之间的可见性:
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 说明 |
|---|---|---|---|---|
| READ UNCOMMITTED(读未提交) | 可能 | 可能 | 可能 | 最低隔离级别 |
| READ COMMITTED(读已提交) | 不可能 | 可能 | 可能 | 大多数数据库默认级别 |
| REPEATABLE READ(可重复读) | 不可能 | 不可能 | 可能 | MySQL默认级别 |
| SERIALIZABLE(序列化) | 不可能 | 不可能 | 不可能 | 最高隔离级别 |
2. 并发问题说明
脏读(Dirty Read):读取到其他事务未提交的数据
不可重复读(Non-repeatable Read):同一事务内多次读取同一数据结果不同
幻读(Phantom Read):同一事务内多次查询返回不同的行集合
3. 隔离级别设置与查看
-- 设置当前会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 设置全局隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 查看当前隔离级别
SELECT @@transaction_isolation;
三、各隔离级别实现机制
1. READ UNCOMMITTED
实现方式:不加锁,直接读取最新数据(包括其他事务未提交的)
问题示例:
-- 事务1
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 事务2(READ UNCOMMITTED)
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 1; -- 可能读取到事务1未提交的修改
2. READ COMMITTED
实现方式:使用MVCC(多版本并发控制),每个语句开始时创建快照
特点:
- 解决脏读问题
- 使用行锁防止写冲突 问题示例:
-- 事务1
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 1; -- 第一次读取
-- 事务2
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;
-- 事务1
SELECT balance FROM accounts WHERE id = 1; -- 第二次读取结果可能不同(不可重复读)
3. REPEATABLE READ(MySQL默认)
实现方式:
事务开始时创建一致性视图
使用MVCC和间隙锁(Gap Lock)防止幻读 特点:
解决脏读和不可重复读
在MySQL中通过间隙锁也解决了大部分幻读问题
示例:
-- 事务1
START TRANSACTION;
SELECT * FROM accounts WHERE balance > 1000; -- 第一次查询
-- 事务2
START TRANSACTION;
INSERT INTO accounts(id, balance) VALUES(11, 1500);
COMMIT;
-- 事务1
SELECT * FROM accounts WHERE balance > 1000; -- 第二次查询结果相同(无幻读)
4. SERIALIZABLE
实现方式:
- 所有SELECT语句自动转为SELECT … FOR SHARE
- 使用严格的锁机制实现串行化
特点:
- 完全串行执行,性能最低
- 解决所有并发问题
四、MySQL中的MVCC机制
多版本并发控制(Multi-Version Concurrency Control)是InnoDB实现隔离级别的核心技术:
- 隐藏字段:
- DB_TRX_ID:最近修改事务ID
- DB_ROLL_PTR:回滚指针
- DB_ROW_ID:行ID
- Undo日志:存储数据修改前的版本
- ReadView:决定事务能看到哪些版本的数据
五、Laravel中的事务实践
1. 基本事务使用
DB::transaction(function () {
$account = Account::find(1);
$account->balance += 100;
$account->save();
Payment::create([
'account_id' => 1,
'amount' => 100
]);
});
2. 手动控制事务
DB::beginTransaction();
try {
$order = Order::create([...]);
Inventory::where('product_id', $productId)
->decrement('quantity', $quantity);
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
// 错误处理
}
3. 设置隔离级别
DB::transaction(function () {
DB::statement('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');
// 业务逻辑
}, 3); // 尝试3次