mysql脏读是怎么产生的_mysql事务问题说明

6次阅读

脏读仅发生在 READ UNCOMMITTED 级别下,MySQL 默认 REPEATABLE READ 可避免脏读但存在幻读;需通过 SERIALIZABLE 或 SELECT…FOR UPDATE 彻底解决幻读,ORM 和连接池可能静默修改隔离级别引发隐患。

mysql 脏读是怎么产生的_mysql 事务问题说明

脏读只发生在 READ UNCOMMITTED 隔离级别下

MySQL 默认隔离级别是 REPEATABLE READ,这个级别下不会发生脏读。只有显式把事务设为 READ UNCOMMITTED,才可能读到其他事务尚未提交的修改。

常见错误现象:应用中执行了 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED,又没意识到后续所有 SELECT 都可能读到未提交数据;或者 ORM(如 Django)配置了全局低隔离级别,导致业务查询意外读取到回滚前的中间状态。

  • 使用场景极少:一般只用于对一致性无要求的统计类查询(如实时在线人数估算),且必须接受“可能读到根本不存在的数据”
  • READ UNCOMMITTED 下,SELECT 不加锁,也不检查行版本,直接读最新写入的记录
  • 一旦另一个事务在你 SELECT 后立刻 ROLLBACK,你就拿到了逻辑上从未成功存在的值

如何复现一次典型的脏读

需要两个并发会话,手动控制事务节奏。关键点在于:Session B 在 Session A 提交前就读取了其修改。

-- Session A START TRANSACTION; UPDATE accounts SET balance = 1000 WHERE id = 1; -- 不执行 COMMIT 或 ROLLBACK,保持事务开启 

-- Session B(已设为 READ UNCOMMITTED)SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; START TRANSACTION; SELECT balance FROM accounts WHERE id = 1; -- 返回 1000,即脏读 -- 此时若 Session A 执行 ROLLBACK,则该 1000 从未真正生效

为什么 REPEATABLE READ 能避免脏读但仍有幻读

REPEATABLE READ 使用多版本并发控制(MVCC),每个事务启动时拍一个快照,后续所有 SELECT 都基于这个快照——它天然过滤掉未提交事务的变更,所以不可能读到脏数据。

但它不阻止其他事务插入新行并提交,因此同一范围的 SELECT 可能两次返回不同数量的行(幻读)。这不是脏读,因为插入的行是已提交的合法数据。

  • 脏读本质是“读到了不该存在的数据”,幻读本质是“读到了新出现的、合法的数据”
  • 想彻底避免幻读,需升级到 SERIALIZABLE(加范围锁)或用 SELECT …… FOR UPDATE 显式锁定区间
  • 注意:innodb_locks_unsafe_for_binlog=ON(已弃用)曾让 RR 行为退化,现代 MySQL 无需担心

ORM 和连接池常悄悄改变隔离级别

Django 的 ATOMIC_REQUESTS、Spring 的 @Transactional(isolation = Isolation.READ_UNCOMMITTED)、或是某些数据库连接池(如 HikariCP)预设的 connection-init-sql,都可能覆盖会话默认隔离级别。

排查时不要只看代码里的 SQL,要确认实际执行前的会话状态:

SELECT @@transaction_isolation, @@session.transaction_isolation;
  • 连接池可能复用连接,而上一个使用者改过隔离级别,导致当前请求“继承”了异常设置
  • Go 的 database/sql 包中,db.Exec("SET SESSION……") 只影响单次调用,但若用 tx, _ := db.Begin(),则需在 tx 上显式 Exec
  • PHP PDO 中,$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, ……) 不影响隔离级别,但 $pdo->exec("SET SESSION ……") 会影响后续所有语句

实际线上环境几乎从不主动启用 READ UNCOMMITTED,真正容易被忽略的是:隔离级别被某处配置静默修改后,脏读成为偶发、难复现的数据异常根源。

星耀云
版权声明:本站原创文章,由 星耀云 2026-01-03发表,共计1729字。
转载说明:转载本网站任何内容,请按照转载方式正确书写本站原文地址。本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。
text=ZqhQzanResources