在高并发系统中,我们经常会遇到这样的场景:
两个用户几乎在同一时间提交请求,更新了同一张表里的同一行数据。
这时,数据库到底会发生什么?会报错吗?会死锁吗?
本文就从 MySQL InnoDB 的事务机制出发,带你搞清楚其中的原理。
一、事务与锁的关系
在 MySQL 中,每一个 UPDATE/DELETE/INSERT 操作,本质上都运行在 事务 中。
-
显式事务:
BEGIN ... COMMIT包裹的事务,锁会一直持有到提交。 -
隐式事务:单条 SQL 没有写事务语句,但 MySQL 会自动开启事务,在语句执行完后立即提交。
不管哪种事务,只要涉及数据修改,就会对目标行加上 行锁。
二、同一时间更新同一行的场景
Session A(显式事务)
BEGIN;
UPDATE product_audit SET edit_record = 'xxx' WHERE id = 1;
-- 成功锁住 id=1
Session B(隐式事务)
三、会发生死锁吗?
不会。
死锁的条件是 至少两个事务,互相等待对方的资源,形成环路。
在这里,A 和 B 都只在争抢 同一行 (id=1):
-
A 已经拿到锁
-
B 只能等待 A 释放
所以这不是死锁,而是 锁等待。
四、可能的结果
-
正常等待
如果 A 很快提交事务:-
A 释放锁
-
B 拿到锁并执行更新
-
两个事务都成功
-
-
等待超时
如果 A 长时间不提交事务:-
B 会一直等待
-
等待超过
innodb_lock_wait_timeout(默认 50 秒),B 报错: -
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
-
-
不会发生死锁
因为涉及的只是同一行,不存在循环依赖。
五、与“更新不同的行”对比
| 场景 | 锁情况 | 结果 |
|---|---|---|
| 更新同一行 | 两个事务争抢同一把锁 | 一个持有,另一个等待,可能超时 |
| 更新不同的行,但顺序不一致 | A 先锁 id=1 等 id=2,B 先锁 id=2 等 id=1 | 出现循环等待 → 死锁 |
六、如何优化?
-
缩短事务时间
尽快提交,减少锁等待。 -
合理设置超时时间
根据业务场景调整innodb_lock_wait_timeout。 -
应用层重试机制
遇到Lock wait timeout错误时,可以重试操作。
七、总结
-
同一时间更新同一行 → 不会死锁,只会发生 锁等待,可能触发超时。
-
更新不同的行,但顺序不一致 → 才可能出现死锁。
-
高并发场景下,优化事务、控制锁范围、合理设计重试逻辑,才能让系统更稳健。
🔑 一句话总结:
更新同一行 → 锁等待;
更新不同的行(顺序不一致) → 死锁风险。
2025-09-11 17:17:15,若文章内容或图片失效,请留言或联系站长反馈!










暂无评论内容