MySQL 事务隔离级别
事务隔离级别决定了并发事务之间的可见性,是平衡性能与数据一致性的关键。
四种隔离级别
| 级别 | 脏读 | 不可重复读 | 幻读 | 性能 |
|---|---|---|---|---|
| READ UNCOMMITTED | 可能 | 可能 | 可能 | 最高 |
| READ COMMITTED | 不可能 | 可能 | 可能 | 较高 |
| REPEATABLE READ | 不可能 | 不可能 | 可能 | 较低 |
| SERIALIZABLE | 不可能 | 不可能 | 不可能 | 最低 |
并发问题说明
SQL
-- 脏读:读到其他事务未提交的数据
-- 事务A 事务B
UPDATE users SET age=20 WHERE id=1;
SELECT age FROM users WHERE id=1; -- 读到20
ROLLBACK;
-- 事务B读到的数据无效
-- 不可重复读:同一事务两次读取结果不同
-- 事务A 事务B
SELECT age FROM users WHERE id=1; -- 18
UPDATE users SET age=20 WHERE id=1;
COMMIT;
SELECT age FROM users WHERE id=1; -- 20,两次结果不同
-- 幻读:同一事务两次查询记录数不同
-- 事务A 事务B
SELECT * FROM users WHERE age>18; -- 3条
INSERT INTO users VALUES(5,'新用户',25);
COMMIT;
SELECT * FROM users WHERE age>18; -- 4条,多了一条"幻影"
设置隔离级别
SQL
-- 全局设置
SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 会话设置
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 下一个事务设置
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 查看隔离级别
SELECT @@transaction_isolation;
SELECT @@global.transaction_isolation;
READ UNCOMMITTED 读未提交
SQL
-- 可能读到脏数据,实际很少使用
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
SELECT * FROM accounts WHERE id = 1; -- 可能读到其他事务未提交的修改
COMMIT;
READ COMMITTED 读已提交
SQL
-- Oracle、SQL Server 默认级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 1; -- 只能看到已提交的数据
-- 其他事务提交后再次查询可能结果不同(不可重复读)
SELECT balance FROM accounts WHERE id = 1;
COMMIT;
REPEATABLE READ 可重复读
SQL
-- MySQL 默认级别,通过 MVCC 实现
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 1; -- 第一次读取
-- 其他事务提交修改后
SELECT balance FROM accounts WHERE id = 1; -- 结果相同
COMMIT; -- 提交后才能看到新数据
MySQL 通过 MVCC 在 REPEATABLE READ 级别也基本解决了幻读问题。
SERIALIZABLE 序列化
SQL
-- 最高隔离级别,所有事务串行执行
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT * FROM accounts; -- 会锁定整表,其他事务等待
COMMIT;
实际开发中常用 READ COMMITTED 或 REPEATABLE READ。
要点总结
- MySQL 默认隔离级别是 REPEATABLE READ
- READ COMMITTED 解决脏读,Oracle 默认
- REPEATABLE READ 解决脏读和不可重复读
- SERIALIZABLE 解决所有问题,但性能最低
- MySQL 通过 MVCC 在 RR 级别基本解决幻读
📝 发现内容有误?点击此处直接编辑