news 2026/4/22 3:41:18

如何避免MySQL死锁?资深DBA的9条黄金法则

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何避免MySQL死锁?资深DBA的9条黄金法则

死锁是数据库里很常见的问题:两个或多个事务互相等待对方释放锁,结果谁也动不了。

MySQL的InnoDB引擎会自己自动检测死锁,并且回滚其中一个事务来解决,但这种情况如果经常遇到的话,会很影响性能和用户体验。

其实,只要注意一些设计细节,就能大大减少甚至避免死锁。

下面是几个最实用的方法:


1. 事务要短,动作要快

事务越长,锁住数据的时间就越久,别人就越容易“撞上”你。

正确做法:只在事务里做必要的数据库操作,别把业务逻辑(比如调接口、算数据)塞进去。

sql

-- 不推荐:事务中混杂业务逻辑 START TRANSACTION; SELECT * FROM users WHERE id = 1; -- 假设此处有耗时的业务处理... UPDATE accounts SET balance = balance - 100 WHERE user_id = 1; UPDATE orders SET status = 'paid' WHERE user_id = 1; COMMIT; -- 推荐:事务只包含必要数据库操作 START TRANSACTION; UPDATE accounts SET balance = balance - 100 WHERE user_id = 1; UPDATE orders SET status = 'paid' WHERE user_id = 1; COMMIT;


2. 所有事务按同一个顺序操作表

这是避免死锁最有效的一招!

比如:如果多个事务都要改 users 和 orders 表,那就统一先改 users,再改 orders。不要有的先改 users,有的先改 orders。

sql

-- 所有地方都这样写: UPDATE users SET ... WHERE id = 1; UPDATE orders SET ... WHERE user_id = 1;

只要顺序一致,就不会出现“A等B、B等A”的循环等待。


3. 给表加合适的索引

InnoDB 的行锁是靠索引来实现的。如果查询没用到索引,MySQL 就可能锁住整张表(或很多无关的行),大大增加死锁风险。

建议

  • 经常用来查或更新的字段(比如 user_id)要建索引。
  • 用 EXPLAIN 看看 SQL 是否命中索引。
sql

CREATE INDEX idx_user_id ON orders(user_id);


4. 别用太高的隔离级别(除非必要)

MySQL 默认是 REPEATABLE READ,它会加“间隙锁”,防止幻读,但也更容易死锁。

如果你的业务能接受“读已提交”(比如允许看到别人刚提交的数据),可以改成:

sql

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

这样锁的范围更小,死锁概率更低。


5. 显式加锁时要小心

如果你要用 SELECT ... FOR UPDATE 锁行,一定要确保:

  • 条件能命中索引;
  • 锁的行尽量少;
  • 事务尽快结束。
sql

-- 安全:通过主键或索引锁定一行 SELECT * FROM accounts WHERE user_id = 1 FOR UPDATE;

如果 user_id 没索引,这条语句可能锁住成千上万行!


6. 应用层要有重试机制

死锁偶尔还是会发生。这时候,应用应该:

  • 捕获死锁错误(MySQL 错误码 1213 或 SQLSTATE '40001');
  • 自动重试几次(比如最多 2~3 次);
  • 每次重试前等一小会儿(比如 100ms、200ms…)。
java

// 伪代码示例 for (int i = 0; i < 3; i++) { try { doDatabaseUpdate(); break; // 成功就退出 } catch (DeadlockException e) { sleep(100 * (i + 1)); // 等一下再试 } }


7. 大批量更新要分批做

一次更新几万行?这很容易锁住大量数据,引发死锁或卡顿。

正确做法:每次只改 500~1000 行,改完提交,再继续。

sql

-- 分批更新 UPDATE large_table SET status = 'done' WHERE create_time < '2023-01-01' AND status != 'done' LIMIT 1000; -- 循环执行,直到没有数据可更新


8. 避免热点数据被频繁修改

比如一个全局计数器,所有请求都去 UPDATE counter SET value = value + 1,那这一行就成了堵点。

解决办法:用分桶计数。

sql

-- 把计数分散到 10 个桶里 UPDATE counter_buckets SET value = value + 1 WHERE name = 'views' AND bucket = FLOOR(RAND() * 10); -- 查总数时再加起来 SELECT SUM(value) FROM counter_buckets WHERE name = 'views';


9. 出问题了怎么查?

看最近一次死锁详情:

sql

SHOW ENGINE INNODB STATUS;

找LATEST DETECTED DEADLOCK部分。

查当前正在运行的事务(MySQL 8.0+):

sql

SELECT * FROM performance_schema.data_locks; SELECT * FROM information_schema.INNODB_TRX;


总结

1.事务要短:别拖着不提交。 2.顺序要一致:所有人按相同顺序改表。 3.索引要到位:避免锁太多无关数据。 4.出错要重试:应用层兜底处理死锁。 5.大批量要分批:别一次锁太多行。

死锁没法完全杜绝,但只要做好这些,基本就不会再被它困扰了!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/20 23:41:57

利用LobeChat构建多语言AI翻译助手平台

利用LobeChat构建多语言AI翻译助手平台 在跨国协作日益频繁的今天&#xff0c;一个能实时理解上下文、准确处理专业术语、还能应对PDF或字幕文件的翻译工具&#xff0c;早已不再是“锦上添花”&#xff0c;而是许多团队的刚需。然而市面上大多数翻译服务依然停留在“输入即输出…

作者头像 李华
网站建设 2026/4/17 16:11:54

从零掌握Mootdx:Python通达信数据分析完整实战指南

从零掌握Mootdx&#xff1a;Python通达信数据分析完整实战指南 【免费下载链接】mootdx 通达信数据读取的一个简便使用封装 项目地址: https://gitcode.com/GitHub_Trending/mo/mootdx 你是否曾经在金融数据分析中遇到过这样的困境&#xff1a;通达信数据格式复杂难懂&a…

作者头像 李华
网站建设 2026/4/18 22:36:51

DeepSeek-7B 边缘部署:嵌入式设备适配与推理速度优化实战

DeepSeek-7B 边缘部署&#xff1a;嵌入式设备适配与推理速度优化实战 摘要&#xff1a; 大型语言模型&#xff08;LLM&#xff09;如 DeepSeek-7B 在云端展现出强大的能力&#xff0c;但其巨大的计算需求和资源消耗限制了其在资源受限的边缘设备和嵌入式系统上的应用。本文将深…

作者头像 李华
网站建设 2026/4/15 13:03:39

终极下载加速方案:用Motrix浏览器扩展实现下载效率翻倍

还在为浏览器下载速度慢如蜗牛而抓狂吗&#xff1f;每次看到下载进度条缓慢爬行&#xff0c;是不是都想砸键盘&#xff1f;别担心&#xff0c;我找到了一个让你下载速度直接起飞的神器——Motrix浏览器扩展&#xff01;&#x1f680; 【免费下载链接】motrix-webextension A br…

作者头像 李华
网站建设 2026/4/18 12:26:40

如何高效学习与工作——提升个人生产力的实用指南

如何高效学习与工作——提升个人生产力的实用指南 在现代社会&#xff0c;学习和工作效率的提升对个人发展至关重要。本文将介绍几种有效的方法&#xff0c;帮助你更好地管理时间&#xff0c;提升专注力&#xff0c;从而实现目标。 制定明确的计划 制定每天、每周的学习和工作计…

作者头像 李华