0

0

mysql中事务的并发控制与数据一致性保证

P粉602998670

P粉602998670

发布时间:2026-01-21 08:15:08

|

819人浏览过

|

来源于php中文网

原创

mysql默认隔离级别下select不加锁,update会触发行锁;快照读无锁,当前读加行锁或间隙锁;索引缺失会导致表级阻塞;insert...on duplicate key update有死锁风险;长事务引发undo膨胀与性能下降。

mysql中事务的并发控制与数据一致性保证

MySQL 默认隔离级别下 SELECT 不加锁,但 UPDATE 会触发行锁

MySQL 的 InnoDB 引擎在 REPEATABLE READ(默认隔离级别)下,普通 SELECT 是快照读(snapshot read),不加锁,也不会阻塞其他事务;而 UPDATEDELETEINSERT 或带 FOR UPDATE/LOCK IN SHARE MODESELECT 是当前读(current read),会加行级记录锁(record lock)或间隙锁(gap lock)。

常见误判是以为“没写 FOR UPDATE 就绝对安全”,其实只要语句命中索引且涉及修改,InnoDB 就会基于聚簇索引加锁——哪怕你只 UPDATE 一个字段,整行记录仍被锁定。

  • WHERE 条件未命中索引,可能升级为表锁(全表扫描 + 每行加锁),并发性能骤降
  • UPDATE t SET x = x + 1 WHERE id = 100UPDATE t SET x = 10 WHERE id = 100 加锁行为一致,锁的是 id = 100 对应的聚簇索引记录
  • 唯一索引等值查询只加 record lock;非唯一索引或范围查询会额外加 gap lock,防止幻读

SELECT ... FOR UPDATE 显式加锁时,必须确保走索引

显式加锁是控制并发最直接的手段,但效果完全依赖执行计划。如果 FOR UPDATE 语句无法使用索引,InnoDB 会退化为锁全表(实际是锁所有扫描到的索引页,但效果接近表级阻塞)。

可通过 EXPLAIN 验证是否走了索引:重点关注 type 字段是否为 constrefrange,以及 key 是否显示实际索引名。

  • ✅ 正确:SELECT * FROM order WHERE order_no = 'ORD2024001' FOR UPDATEorder_no 有唯一索引)
  • ❌ 危险:SELECT * FROM order WHERE status = 'pending' FOR UPDATEstatus 无索引 → 全表扫描 + 行锁堆积)
  • ⚠️ 注意:FOR UPDATE 在可重复读下也会加 gap lock,比如 WHERE id > 100 会锁住 (100, +∞) 的间隙,不只是已有记录

INSERT ... ON DUPLICATE KEY UPDATE 的原子性与死锁风险

该语句在存在唯一键冲突时自动转为 UPDATE,看似能避免先查后更的竞态,但它内部仍分两步:先尝试插入,失败则执行更新。整个过程是原子的,但加锁行为复杂——InnoDB 会对插入意向间隙锁(insert intention gap lock)和后续可能触发的记录锁同时持有。

启科网络PHP商城系统
启科网络PHP商城系统

启科网络商城系统由启科网络技术开发团队完全自主开发,使用国内最流行高效的PHP程序语言,并用小巧的MySql作为数据库服务器,并且使用Smarty引擎来分离网站程序与前端设计代码,让建立的网站可以自由制作个性化的页面。 系统使用标签作为数据调用格式,网站前台开发人员只要简单学习系统标签功能和使用方法,将标签设置在制作的HTML模板中进行对网站数据、内容、信息等的调用,即可建设出美观、个性的网站。

下载

高并发下容易因锁顺序不一致引发死锁,尤其当多个事务按不同顺序操作同一组主键/唯一键时。

  • 死锁日志中常出现 lock_mode X locks rec but not gap waitinglock_mode X locks gap before rec insert intention waiting 并存
  • 缓解方式:确保所有业务逻辑按相同字段顺序(如始终按 user_id 升序)批量处理;或改用 INSERT IGNORE + 应用层重试
  • 注意:ON DUPLICATE KEY UPDATE 中的 UPDATE 部分不会触发 BEFORE/AFTER UPDATE 触发器

长事务导致 MVCC 快照过旧,引发 Undo Log 膨胀与查询变慢

InnoDB 通过 Undo Log 维护多版本,每个事务开始时确定自己的“快照视图”。如果一个事务长时间不提交(比如应用端忘记 COMMIT 或卡在慢查询里),它持有的低水位(low watermark)会阻止系统清理早于该时间点的 undo 日志,导致 ibdata1 或独立 undo 表空间持续增长,甚至撑爆磁盘。

更隐蔽的影响是:其他事务的 SELECT 需要回溯更多版本链,CPU 和 buffer pool 压力上升,简单查询响应变慢。

  • 监控活跃长事务:SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 60
  • 设置超时强制回滚:SET SESSION innodb_lock_wait_timeout = 30(仅对锁等待生效),或应用层统一加事务超时控制
  • 避免在事务内做 HTTP 请求、文件读写、sleep 等外部耗时操作
SELECT 
  trx_id,
  trx_state,
  trx_started,
  trx_wait_started,
  TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) AS duration_sec,
  trx_query
FROM information_schema.INNODB_TRX 
WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 120
ORDER BY duration_sec DESC;

真正难处理的不是锁本身,而是锁和业务逻辑节奏错配:比如一个本该秒级完成的扣库存事务,因为上游调用方重试策略激进,导致同一订单被多个线程反复争抢同一条记录,间隙锁不断叠加,最终拖垮整个订单库。这种问题光看 SQL 语法看不出毛病,得结合压测时的 SHOW ENGINE INNODB STATUS 输出和应用调用链一起看。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

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

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

1133

2023.10.12

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

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

340

2023.10.27

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

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

381

2024.02.23

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

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

2152

2024.03.06

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

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

380

2024.03.06

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

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

1683

2024.04.07

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

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

585

2024.04.29

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

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

440

2024.04.29

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

3

2026.03.11

热门下载

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

精品课程

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

共48课时 | 2.5万人学习

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

共3课时 | 0.3万人学习

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

共1课时 | 847人学习

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

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