mysql并发情况下如何保证数据正确_mysql一致性处理方法
发布时间 - 2026-01-21 00:00:00 点击率:次应使用SELECT ... FOR UPDATE加行级写锁防止并发更新丢失,确保WHERE条件命中索引以避免表锁,并配合INSERT ... ON DUPLICATE KEY UPDATE处理“查再插”竞态;READ COMMITTED下需警惕幻读,跨服务场景须依赖应用层幂等或分布式事务。
用 SELECT ... FOR UPDATE 锁住要更新的行
在事务中修改某条记录前,必须先加行级写锁,否则并发读-改-写会导致覆盖或丢失更新。比如两个事务同时读取余额为 100 的账户,各自加 50 后写回,最终变成 150 而不是预期的 200。
正确做法是在 BEGIN 后立即执行带锁查询:
START TRANSACTION; SELECT balance FROM accounts WHERE id = 123 FOR UPDATE; -- 此时其他事务对 id=123 的行执行 SELECT ... FOR UPDATE 或 UPDATE 会被阻塞 UPDATE accounts SET balance = balance + 50 WHERE id = 123; COMMIT;
注意:FOR UPDATE 只在可重复读(REPEATABLE READ)隔离级别下才真正锁定索引覆盖的行;如果 WHERE 条件没走索引,会升级为表锁。
避免长事务 + 显式控制锁范围
锁持有时间越长,阻塞越多,死锁概率越高。常见错误是把耗时操作(如 HTTP 调用、文件读写)放进事务里。
- 只把真正需要原子性的 DB 操作包进事务
- 确保
WHERE条件命中主键或唯一索引,避免锁住不相关行 - 批量更新时,分页或按主键范围拆成多个小事务,不要一次
UPDATE ... LIMIT 10000 - 确认 autocommit 关闭(
SET autocommit = 0),否则每条语句自动提交,FOR UPDATE失效
用 INSERT ... ON DUPLICATE KEY UPDATE 替代“查再插”
“先查是否存在,不存在则插入”这种逻辑在并发下必然产生竞态:两个事务都查到不存在,然后都插入,触发唯一键冲突或重复数据。
直接用原子语句替代:
INSERT INTO user_points (user_id, points) VALUES (123, 10) ON DUPLICATE KEY UPDATE points = points + 10;
前提是 user_id 有唯一约束(主键或 UNIQUE 索引)。该语句内部由 MySQL 自动处理冲突,不会报错也不会丢更新。
注意:如果业务需要区分“本次是插入还是更新”,可通过 ROW_COUNT() 判断影响行数,但不能依赖 LAST_INSERT_ID() —— 它在 ON DUPLICATE KEY UPDATE 场景下行为不可靠。
读已提交(READ COMMITTED)下慎用非锁定读
默认的 REPEATABLE READ 隔离级别能防止不可重复读,但代价是间隙锁(Gap Lock)更重;而 READ COMMITTED 下每次 SELECT 都读最新已提交版本,不加间隙锁,看似轻量,却容易引发幻读问题——尤其在“检查约束+插入”类逻辑中。
例如判断订单号未被使用,然后插入新订单:
- 事务 A 查
SELECT COUNT(*) FROM orders WHERE order_no = 'NO2025001'→ 0 - 事务 B 插入
'NO2025001'并提交 - 事务 A 继续插入 → 唯一键冲突
这种场景不能靠隔离级别解决,必须用 SELECT ... FOR UPDATE 或唯一索引+INSERT ... ON DUPLICATE KEY UPDATE 这类原子机制兜底。
真正难处理的不是单条 SQL 的一致性,而是跨表、跨服务、含外部依赖的业务逻辑。MySQL 的锁和事务只能保它自己那块数据,一旦涉及 Redis 缓存更新、MQ 发消息、第三方支付回调,就得靠应用层补偿、幂等设计或分布式事务框架来兜住——这些已经超出 MySQL 本身能力范围了。
# mysql
# redis
# red
# sql
# 分布式
# count
# for
# select
# 并发
# http
# 主键
# 不存在
# 死锁
# 一键
# 锁住
# 应用层
# 是在
# 多个
# 这类
# 分页
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel路由Route怎么设置_Laravel基础路由定义与参数传递规则【详解】
DeepSeek是免费使用的吗 DeepSeek收费模式与Pro版本功能详解
如何在万网主机上快速搭建网站?
如何在万网自助建站中设置域名及备案?
手机软键盘弹出时影响布局的解决方法
Python自然语言搜索引擎项目教程_倒排索引查询优化案例
如何用PHP工具快速搭建高效网站?
如何生成腾讯云建站专用兑换码?
html5源代码发行怎么设置权限_访问权限控制方法与实践【指南】
齐河建站公司:营销型网站建设与SEO优化双核驱动策略
英语简历制作免费网站推荐,如何将简历翻译成英文?
Laravel Admin后台管理框架推荐_Laravel快速开发后台工具
Laravel中的Facade(门面)到底是什么原理
Android GridView 滑动条设置一直显示状态(推荐)
详解Oracle修改字段类型方法总结
免费视频制作网站,更新又快又好的免费电影网站?
js实现点击每个li节点,都弹出其文本值及修改
如何制作一个表白网站视频,关于勇敢表白的小标题?
详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)
Linux后台任务运行方法_nohup与&使用技巧【技巧】
Laravel如何实现全文搜索_Laravel Scout集成Algolia或Meilisearch教程
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?
网站制作软件免费下载安装,有哪些免费下载的软件网站?
Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区
Laravel怎么实现前端Toast弹窗提示_Laravel Session闪存数据Flash传递给前端【方法】
Laravel如何生成PDF或Excel文件_Laravel文档导出工具与使用教程
javascript日期怎么处理_如何格式化输出
Python文本处理实践_日志清洗解析【指导】
详解MySQL数据库的安装与密码配置
Laravel N+1查询问题如何解决_Eloquent预加载(Eager Loading)优化数据库查询
如何在阿里云虚拟服务器快速搭建网站?
Laravel如何从数据库删除数据_Laravel destroy和delete方法区别
如何彻底卸载建站之星软件?
潮流网站制作头像软件下载,适合母子的网名有哪些?
Laravel怎么返回JSON格式数据_Laravel API资源Response响应格式化【技巧】
Android实现代码画虚线边框背景效果
如何在 React 中条件性地遍历数组并渲染元素
Win11怎么开启自动HDR画质_Windows11显示设置HDR选项
如何用y主机助手快速搭建网站?
JavaScript如何实现倒计时_时间函数如何精确控制
Laravel怎么解决跨域问题_Laravel配置CORS跨域访问
Laravel如何发送系统通知?(Notification渠道示例)
如何在Windows环境下新建FTP站点并设置权限?
企业在线网站设计制作流程,想建设一个属于自己的企业网站,该如何去做?
Win11怎么查看显卡温度 Win11任务管理器查看GPU温度【技巧】
C++时间戳转换成日期时间的步骤和示例代码
Laravel数据库迁移怎么用_Laravel Migration管理数据库结构的正确姿势
INTERNET浏览器怎样恢复关闭标签页_INTERNET浏览器标签恢复快捷键与方法【指南】
香港服务器网站卡顿?如何解决网络延迟与负载问题?


