先问:读到的数据提交了吗?
脏读的核心是读到了另一个事务尚未提交的数据。注意“未提交”三个字,这是脏读和另外两个概念最直接的分界线。比如事务 A 修改了账户余额但还没提交,事务 B 已经读到了这个新余额;后来事务 A 回滚,事务 B 之前读到的就是不可靠的数据。
考试题干如果反复强调“另一个事务尚未提交”“随后回滚”“读到了临时数据”,优先想到脏读。不要一看到两次读取结果不同就马上选不可重复读,先看第一次读到的值是不是来自未提交事务。
| 并发异常 | 核心判断 | 老师提醒 |
|---|---|---|
| 脏读 | 读到未提交数据 | 关键词是未提交、回滚、临时结果 |
| 不可重复读 | 同一行数据前后读取结果不同 | 关键词是同一条记录被修改或删除 |
| 幻读 | 同一范围内记录数量变化 | 关键词是一批记录、多出或少了行 |
| 丢失更新 | 两个事务更新互相覆盖 | 关键词是后写覆盖前写 |
不可重复读盯的是“同一行”
不可重复读通常发生在一个事务内,两次读取同一条记录,结果不一样。原因可能是另一个事务在中间修改并提交了这条记录。它关注的是一条已经存在的记录值发生变化,或者这条记录被删除。
例如事务 A 第一次查询订单 1001 的状态是“待支付”,事务 B 把它改成“已支付”并提交,事务 A 第二次再查订单 1001,状态变了。这个例子里,不是多了一批新订单,而是同一条订单前后不一致。
考场小口诀
脏读:读到了别人还没确认的草稿。
不可重复读:同一条记录,前后读出来不一样。
幻读:同一个查询范围,第二次像多了或少了几条记录。
幻读盯的是“范围里的记录数”
幻读看起来也像前后查询不一致,但它通常不是同一行的字段值变了,而是某个范围查询的结果集变了。比如事务 A 查询“金额大于 1000 的订单”得到 5 条记录;事务 B 插入一条金额 2000 的订单并提交;事务 A 再查同样条件,变成 6 条。
这就是为什么很多老师会说:不可重复读看一行,幻读看一批。只要题干出现范围查询、满足条件的记录数量、插入新记录这类描述,就要警惕幻读,而不是只按“第二次结果不同”去判断。
| 题干描述 | 更可能是 | 不要误判为 |
|---|---|---|
| 读到了未提交后又回滚的数据 | 脏读 | 不可重复读 |
| 同一订单状态前后不同 | 不可重复读 | 幻读 |
| 同一条件查询多出几条记录 | 幻读 | 不可重复读 |
| 两个事务同时改库存,后提交覆盖前提交 | 丢失更新 | 脏读 |
隔离级别不是越高越随便选
事务隔离级别越高,通常能减少更多并发异常,但并发性能也可能下降。考试不会只让你喊“串行化最安全”,更常见的是让你理解不同隔离级别为什么存在:系统需要在正确性和并发性能之间做取舍。
复习时可以把这类题放在 ACID 的 Isolation 下面理解。隔离性不是一句“互不影响”就结束了,它具体会落到脏读、不可重复读、幻读这些可观察的问题上。题干一旦出现这几个词,先别想索引、备份和视图,先回到事务隔离。
相关题目解析
下面这些题目和本专题的判断方法关联较强,适合读完概念后回到具体题干里校验理解。
- 事务隔离级别用于解决哪些并发问题?事务隔离级别 / 数据库事务隔离级别