0

0

mysql并发读写会产生哪些问题_mysql常见并发场景说明

P粉602998670

P粉602998670

发布时间:2026-01-04 12:44:02

|

570人浏览过

|

来源于php中文网

原创

脏读、不可重复读、幻读分别由事务B未提交更新、已提交更新同一行、已提交插入新行触发;MySQL默认RR级通过MVCC+临键锁防前两者,但幻读仅对快照读有效,当前读仍可能发生。

mysql并发读写会产生哪些问题_mysql常见并发场景说明

脏读、不可重复读、幻读到底怎么触发?

这三个问题不是理论概念,而是真实 SQL 执行顺序下必然出现的现象。关键在于:**事务 A 读取时,事务 B 正在做什么、是否已提交、操作的是同一行还是新插入的行**。

  • 脏读:事务 A 执行 SELECT 时,事务 B 刚 UPDATE 了一行但还没 COMMIT;A 读到了这行“未定稿”,B 后续 ROLLBACK → A 的读取结果就失效了。
  • 不可重复读:事务 A 第一次 SELECT id=100 得到 name='Alice';事务 B 提交了 UPDATE users SET name='Bob' WHERE id=100;A 再次 SELECT id=100,得到 name='Bob' —— 同一行值变了。
  • 幻读:事务 A 执行 SELECT * FROM orders WHERE status='pending' 返回 3 条;事务 B 插入一条新 status='pending' 记录并 COMMIT;A 再次执行相同查询,返回 4 条 —— 行数变多了,像“幻影”。注意:这不是更新同一行,而是满足条件的新行被插入。

MySQL 默认的 REPEATABLE READ 真的能防住所有问题吗?

不能。MySQL InnoDB 的默认隔离级别是 REPEATABLE READ,它靠 MVCC + Next-Key Lock(临键锁)实现,能防脏读和不可重复读,但对幻读只做“部分防护”——仅针对普通 SELECT(快照读)有效;一旦用了当前读(如 SELECT ... FOR UPDATEUPDATEDELETE),幻读仍可能发生,尤其在范围条件上。

  • 例如:事务 A 执行 SELECT * FROM t WHERE c > 10 FOR UPDATE 锁住满足条件的记录和间隙;事务 B 尝试插入 c=15 会被阻塞 → 这是幻读被锁挡住。
  • 但如果事务 B 插入的是 c=5(不在 A 的查询范围内),或 A 没加锁直接 SELECT(快照读),那 B 的插入就能成功,A 再查就会“看到幻影”。
  • 真正彻底解决幻读,只有 SERIALIZABLE 隔离级别,但它会让所有并发 SELECT 变成串行,线上基本不用。

写-写冲突:为什么两个 UPDATE 会互相卡住?

当两个事务同时想改同一行,InnoDB 必须用排他锁(X 锁)互斥。谁先拿到锁谁先改,后到的只能等 —— 这就是锁等待。如果等待超时(默认 innodb_lock_wait_timeout = 50 秒),会报错:Lock wait timeout exceeded; try restarting transaction

TabTab AI
TabTab AI

首个全链路 Data Agent,让数据搜集、处理到深度分析一步到位。

下载
  • 典型场景:秒杀扣库存,多个请求同时执行 UPDATE goods SET stock = stock - 1 WHERE id = 123 AND stock > 0
  • 陷阱:即使 SQL 带了 AND stock > 0 条件,InnoDB 仍会对匹配的索引记录(甚至间隙)加 X 锁,后续请求必须排队。
  • 优化方向不是“去掉锁”,而是缩短锁持有时间:确保该语句走索引、避免大事务、减少其他无关 SQL 在同一事务中。

读-写并发下,MVCC 是怎么悄悄帮你躲开锁的?

MVCC 不是魔法,它是通过给每行数据维护多个版本(由 DB_TRX_ID 标记),配合事务启动时生成的 ReadView,让普通 SELECT 读取“快照”,而不是最新行 —— 所以读不加锁,也不阻塞写。

  • 关键点:REPEATABLE READ 下,事务第一次 SELECT 生成 ReadView,之后所有快照读都复用它;READ COMMITTED 则每次 SELECT 都新建 ReadView,所以能看到其他事务已提交的修改(即允许不可重复读)。
  • 注意:SELECT ... LOCK IN SHARE MODEFOR UPDATE 是当前读,绕过 MVCC,直接加 S/X 锁,会阻塞其他写操作。
  • 一个易忽略的事实:MVCC 只解决读-写冲突,对写-写冲突完全不管 —— 两个 UPDATE 依然要抢锁,哪怕它们读的是不同快照。

最常被低估的一点:并发问题从来不是孤立存在的。比如你调高了隔离级别防幻读,却没意识到它会让更多语句升级为当前读,从而增加锁竞争;又比如你依赖 MVCC 实现无锁读,却在事务里混进了 SELECT ... FOR UPDATE,瞬间打破快照一致性。真正的并发控制,是隔离级别、锁策略、SQL 写法、应用重试逻辑四者咬合的结果,缺一不可。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

676

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

320

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

346

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1090

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

356

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

674

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

570

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

411

2024.04.29

mc.js网页版入口地址大全
mc.js网页版入口地址大全

本专题整合了mc.js网页版入口地址大全以及mc.js1.8.8版本汇总,阅读专题下面的文章了解更多详细内容。

34

2026.01.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 1.6万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 779人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号