MySQL 的事务隔离级别(Transaction Isolation Levels)用于控制 事务之间的可见性,是解决并发一致性问题的关键机制。
🔒 MySQL 提供的 4 种事务隔离级别
| 隔离级别(英文) | 中文名 | 可能产生的问题 |
|---|---|---|
READ UNCOMMITTED | 读未提交 | ✅ 脏读、不可重复读、幻读 |
READ COMMITTED | 读已提交 | ❌ 脏读;✅ 不可重复读、幻读 |
REPEATABLE READ(默认) | 可重复读 | ❌ 脏读、不可重复读;✅ 幻读(MySQL 用 Gap Lock 避免) |
SERIALIZABLE | 串行化 | ❌ 所有并发问题,但性能最差 |
🧪 常见并发问题对照表
| 并发问题 | 描述 |
|---|---|
| 脏读 | 读到其他事务尚未提交的数据 |
| 不可重复读 | 同一事务中多次读到不同值(被其他事务修改了) |
| 幻读 | 同一事务中前后查询结果行数不一致(被其他事务插入了新行) |
🏗️ 设置事务隔离级别
✅ 查看当前隔离级别:
SELECT @@tx_isolation; -- MySQL 5.x
SELECT @@transaction_isolation; -- MySQL 8+
✅ 设置当前会话隔离级别:
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
✅ 设置全局隔离级别(重启失效):
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
⚠️ 全局设置只影响新连接,已存在连接不会改变。
🚀 示例对比(以“可重复读”为例)
假设事务 A 和事务 B 并发执行:
-- 事务 A
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 1;
-- 同时事务 B 更新该账户:
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
COMMIT;
-- 事务 A 再次读取
SELECT balance FROM accounts WHERE id = 1;
在不同隔离级别下行为:
| 隔离级别 | 第一次和第二次读取是否相同? |
|---|---|
| READ UNCOMMITTED | ❌ 不同(可能脏读) |
| READ COMMITTED | ❌ 不同 |
| REPEATABLE READ | ✅ 相同(可重复读) |
| SERIALIZABLE | ✅ 相同(严格串行) |
⚙️ MySQL 默认:REPEATABLE READ
MySQL 默认采用 REPEATABLE READ,并结合 MVCC(多版本并发控制) 实现可重复读,同时使用 间隙锁(Gap Lock) 避免幻读。
📘 总结口诀:
读未提交最危险,脏读幻读都能现;
读已提交不脏读,不可重复仍可见;
可重复读最常用,避免重复防幻影;
串行化最严格,性能消耗最可怜。