一、并发事务带来的问题
并发事务如果不加控制,会带来四类问题,从轻到重分别是:脏读、不可重复读、幻读
1、脏读:读到了别的事务还没提交的数据。
事务 A:把余额 100 → 200(未提交)
事务 B:读余额,读到 200
事务 A:回滚,余额变回 100
事务 B 读到的 200 是从未真正生效过的数据,基于它做的判断可能是错的。
危害:读到"脏"数据,最终这个值不存在。
2、不可重复读:同一个事务内,两次读同一行,结果不一样。
事务 A:读余额,得到 100
事务 B:把余额改成 200 并提交
事务 A:再读余额,得到 200
同一个事务里,两次读结果不同,因为中间被别人改了。
危害:事务内数据前后不一致。
注意和脏读的区别:
脏读:读到未提交的数据
不可重复读:读到已提交的数据,但两次读之间被别人改了
3、幻读:同一个事务内,两次执行同样的范围查询,第二次多出了"幻影行"。
事务 A:查 id > 100 的记录,得到 5 条
事务 B:插入一条 id = 101 的记录并提交
事务 A:再查 id > 100,得到 6 条
多出来的那条就是"幻影行"。
和不可重复读的区别:
不可重复读:针对同一行,值变了
幻读:针对一个范围,行数变了(多了或少了)
二、隔离级别
SQL 标准定义了四种隔离级别,级别越高,一致性越强,但并发性能越低。
其中可重复读是 mysql 默认的隔离级别
| 隔离级别 | 脏读 | 不可重复读 | 幻读 | 说明 |
|---|---|---|---|---|
| READ UNCOMMITTED 读未提交 | ❌ | ❌ | ❌ | 最低级别,几乎不加锁 |
| READ COMMITTED 读已提交 | ✅ | ❌ | ❌ | 只能读已提交数据(Oracle 默认) |
| REPEATABLE READ 可重复读 | ✅ | ✅ | ❌ | 同一事务内多次读结果一致(MySQL 默认) |
| SERIALIZABLE 串行化 | ✅ | ✅ | ✅ | 最高级别,事务串行执行 |