MySQL 事务与隔离级别入门

理解 ACID、事务提交与回滚、脏读、不可重复读、幻读,以及 MySQL 常见隔离级别与并发异常的关系。

写在前面:合法学习边界

本文讲解数据库事务原理。相关测试请在自建环境完成,不要对生产数据库执行锁表、大事务或回滚操作。

一、什么是事务

事务是把一组数据库操作打包成一个原子单元:要么全部成功,要么全部回滚。

典型场景:

1
2
3
转账:扣款 + 加款
下单:减库存 + 建订单
注册:插用户 + 初始化配置

一个事务里如果有一步失败,前面的操作都要能回滚,不能留下“只扣了钱没加钱”的半成品状态。

二、ACID 是什么

1
2
3
4
A(原子性):要么全做,要么全不做
C(一致性):执行前后数据状态都符合约束
I(隔离性):并发事务之间互相隔离
D(持久性):提交后数据不丢

初学者最容易忽略的是 I(隔离性):多个事务同时跑的时候,怎么保证彼此看不到中间态。

三、并发会带来哪些问题

1. 脏读

事务 A 修改了数据但还没提交,事务 B 读到了这个未提交的值。A 一旦回滚,B 读到的是“不存在的数据”。

1
B 读到了 A 未提交的修改 → 脏读

2. 不可重复读

同一个事务里,两次读同一行,结果不一样。

1
2
3
事务内第一次读到 v1
期间别的事务提交了修改
事务内第二次读到 v2

3. 幻读

同一个事务里,两次查询同一范围,多出来(或消失)了行。

1
2
3
第一次查,符合条件有 2 行
别的事务插入了一行并提交
第二次查,变成 3 行

四、MySQL 的隔离级别

1
2
3
4
READ UNCOMMITTED:可以读未提交 → 可能脏读
READ COMMITTED:只能读已提交 → 避免脏读,仍可能不可重复读
REPEATABLE READ:事务内读结果一致 → 避免不可重复读(MySQL 默认)
SERIALIZABLE:完全串行 → 最强隔离,性能最低

InnoDB 默认是 REPEATABLE READ,配合 MVCC 能解决大部分不可重复读问题,但幻读仍可能出现在特定范围查询中。

五、防御与使用建议

1
2
3
4
5
事务尽量短,减少锁持有时间
按需选择隔离级别,不无脑 SERIALIZABLE
大事务拆小,避免长时间锁表
关键数据加唯一约束兜底
对慢事务、长事务做监控

六、小结

事务不是“用了就安全”,隔离级别决定了并发下的可见性。理解脏读、不可重复读、幻读三种异常和 MySQL 的隔离级别,才能解释为什么有时会读到“奇怪”的数据。