跳转到主内容
极星编程网:以代码为星,赴技术山海!

mysql事务并发会带来哪些问题_mysql脏读幻读不可重复读

脏读、不可重复读、幻读分别对应事务隔离级别的三类问题:脏读在READ UNCOMMITTED下发生,READ COMMITTED及以上可避免;不可重复读在READ COMMITTED下出现,REPEATABLE READ通过MVCC解决;幻读在REPEATABLE READ下仍可能影响当前读,SERIALIZABLE才能完全避免。 脏读:读到了别人还没提交的修改 事务 A 修改了一行数据但没提交,事务 B 此时读到了这行“脏”数据。一旦 A 回滚,B 读到的就是根本不存在的状态。
READ UNCOMMITTED
隔离级别下必然发生;
READ COMMITTED
及以上可避免 典型场景:报表系统误把临时草稿当真实数据统计 错误现象不是报错,而是业务逻辑出错——比如用户看到余额变多了,实际扣款却失败了 MySQL 默认是
REPEATABLE READ
,所以默认不会脏读,但显式设成
READ UNCOMMITTED
就会 不可重复读:同一事务里两次 SELECT 结果不一致 事务 A 第一次读某行,事务 B 提交了对这行的 UPDATE 或 DELETE,A 再读一次,发现数据变了——这不是幻觉,是真实更新被看到了。
READ COMMITTED
级别下会发生;
REPEATABLE READ
(MySQL 默认)用 MVCC 快照避免了它 注意:这里改的是“已有行”,不是新增或删除行——那是幻读的范畴 示例:
SELECT balance FROM accounts WHERE id = 1;
执行两次,中间被别人
UPDATE accounts SET balance = 100 WHERE id = 1;
并提交,第二次结果就不同 性能影响:MVCC 在
REPEATABLE READ
下需维护多个版本,undo log 增长快,长事务会拖慢 purge 线程 幻读:查不到的记录突然“冒出来” 事务 A 按条件查了一批记录(比如
SELECT * FROM orders WHERE status = 'pending';
),事务 B 插入一条满足该条件的新记录并提交,A 再次执行相同查询,发现多了一条“幻影”记录。 MySQL(Linux) MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。 下载 MySQL 的
REPEATABLE READ
用间隙锁(gap lock)+ 行锁 + Next-Key Lock,在大多数情况下阻止幻读——但仅限于当前读(如
SELECT ... FOR UPDATE
或
UPDATE
带条件) 纯快照读(普通
SELECT
)在
REPEATABLE READ
下不会看到新插入的行,所以“感觉不到”幻读;但如果你做
UPDATE ... WHERE status = 'pending'
,可能意外更新到 B 刚插入的那条,这就是幻读的实际影响 真正能完全避免幻读的只有
SERIALIZABLE
,但它会让并发写变成排队,吞吐暴跌 常见坑:开发以为加了事务就万事大吉,结果在
REPEATABLE READ
下做“先查后插”的业务逻辑(如防重单),没加
SELECT ... FOR UPDATE
,导致两条一模一样的订单入库 怎么选隔离级别?别只看理论 MySQL 默认
REPEATABLE READ
是有代价的:间隙锁可能引发死锁,长事务让 undo log 膨胀,备份时
mysqldump --single-transaction
依赖它但也会被阻塞。 如果业务能接受“每次读都看到最新已提交数据”,且没有范围更新需求,
READ COMMITTED
更轻量,还减少锁冲突 高并发写+范围条件更新(比如批量关单、改状态),务必确认是否用了
SELECT ... FOR UPDATE
加锁,否则幻读隐患藏在逻辑深处
SERIALIZABLE
几乎不用在 OLTP 场景——它会让所有
SELECT
都隐式加锁,连简单查询都可能互相等待 最常被忽略的一点:应用层重试逻辑和隔离级别要匹配。比如在
READ COMMITTED
下重试 SELECT+UPDATE,可能比
REPEATABLE READ
下更安全;反过来,若假设“同一事务内数据不变”,却用了
READ COMMITTED
,就会出错

相关文章