上一篇
"老王!快来看看!订单系统突然卡死了,前端报错说'锁等待超时'!" 凌晨2点,运维小张的紧急电话把你从梦中惊醒。😱 你揉着眼睛连上服务器,发现满屏的Error 3572 (ER_LOCK_NOWAIT)
错误——这该死的锁等待问题又来了!
别慌!作为经历过多次数据库"深夜惊魂"的老司机,今天我们就来彻底搞定这个磨人的小妖精。💪
错误全称:ER_LOCK_NOWAIT
错误代码:3572
SQL状态:HY000
触发条件:当使用NOWAIT
或SKIP LOCKED
选项时,如果无法立即获取锁就会抛出此错误(MySQL 8.0+特性)
与常见的1205 (Lock wait timeout exceeded)
不同,3572错误是主动放弃等待的结果,通常出现在以下场景:
SELECT ... FOR UPDATE NOWAIT
SELECT ... FOR UPDATE SKIP LOCKED
READ COMMITTED
时的高并发更新-- 查看当前阻塞的锁 SELECT * FROM performance_schema.data_locks WHERE LOCK_STATUS = 'WAITING'; -- 查看长时间运行的事务(重点关注Time>60s的) SELECT * FROM information_schema.innodb_trx ORDER BY trx_started DESC LIMIT 10;
找到阻塞源头后,用这个"杀手锏":
-- 替换[trx_mysql_thread_id]为上面查询到的ID KILL [trx_mysql_thread_id];
-- 适当增加锁等待超时时间(默认50秒) SET GLOBAL innodb_lock_wait_timeout = 120;
-- 坏例子(大事务) START TRANSACTION; UPDATE orders SET status = 'paid' WHERE user_id = 100; UPDATE inventory SET stock = stock - 1 WHERE item_id IN (...); -- 几十个其他操作... COMMIT; -- 好例子(拆分事务) START TRANSACTION; UPDATE orders SET status = 'paid' WHERE user_id = 100; COMMIT; START TRANSACTION; UPDATE inventory SET stock = stock - 1 WHERE item_id = 101; COMMIT;
-- 常规写法(可能阻塞) SELECT * FROM accounts WHERE user_id = 5 FOR UPDATE; -- 优化写法(8.0+特性) -- 方案A:不等待直接报错 SELECT * FROM accounts WHERE user_id = 5 FOR UPDATE NOWAIT; -- 方案B:跳过被锁定的行 SELECT * FROM accounts FOR UPDATE SKIP LOCKED;
-- 在锁冲突严重的表上检查索引 EXPLAIN SELECT * FROM orders WHERE user_id = 100 FOR UPDATE; -- 确保WHERE条件使用索引列 ALTER TABLE orders ADD INDEX idx_user (user_id);
设置这些预警指标(参考值):
innodb_row_lock_waits
> 100次/分钟innodb_row_lock_time_avg
> 500ms用这个SQL创建监控视图:
CREATE VIEW lock_monitor AS SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread, r.trx_query waiting_query, b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query FROM performance_schema.data_lock_waits w INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_engine_transaction_id INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_engine_transaction_id;
对于秒杀类场景,可以尝试这些黑魔法✨:
-- 乐观锁实现 UPDATE products SET stock = stock - 1, version = version + 1 WHERE item_id = 123 AND version = [当前版本]; -- 直接递减(有限场景) UPDATE inventory SET stock = stock - 1 WHERE item_id = 456 AND stock > 0;
遇到3572错误时,按这个顺序检查:
NOWAIT/SKIP LOCKED
?(是→预期行为)innodb_trx
表)lock_monitor
视图)EXPLAIN
分析)记住老王的话:"锁等待不是错误,是数据库在哭诉你的设计有问题!" 😉 下次再遇到3572错误,希望你能优雅地解决它,而不是在深夜给同事打求救电话啦!
本文由 卑茂学 于2025-08-03发表在【云服务器提供商】,文中图片由(卑茂学)上传,本平台仅提供信息存储服务;作者观点、意见不代表本站立场,如有侵权,请联系我们删除;若有图片侵权,请您准备原始证明材料和公证书后联系我方删除!
本文链接:https://vps.7tqx.com/wenda/522018.html
发表评论