MySQL InnoDB多用户并发写UPDATE自动加锁机制及串行执行设置咨询
MySQL InnoDB UPDATE并发操作可靠性说明
内置默认机制是否能保障安全
- InnoDB执行
UPDATE语句时会自动提供锁保障:执行写操作前会给目标行加排他锁(X锁),该锁会持续持有到当前事务提交/回滚,同一时间仅允许一个事务持有某行的X锁,其余针对该行的写请求会进入阻塞队列按顺序执行,完全避免了多并发下的更新丢失问题。 - 单条
UPDATE语句本身具备原子性,要么全部执行成功,要么完全不生效,不会出现执行一半的中间状态。 - 针对你提到的并发扣库存场景,只要扣减逻辑写在单条SQL内(例如
UPDATE goods SET stock = stock - 1 WHERE id = 123 AND stock > 0),使用InnoDB默认配置就可以完全保障计算结果正确,不会出现超卖或者库存计算错误的问题。
什么场景需要额外配置
默认机制仅保障单条写操作的原子性和锁安全,如果你的业务逻辑是先查库存、再在应用层做扣减计算、最后执行UPDATE,这种拆分的操作逻辑会出现更新丢失,需要额外做并发控制。
串行执行的配置方案
如果需要让多条操作也按顺序串行执行,可以选择以下方案:
- 调整事务隔离级别到可串行化(SERIALIZABLE):这是SQL标准定义的最高隔离级别,InnoDB会自动给所有查询加间隙锁,所有读写操作严格按串行顺序执行,完全避免并发冲突。可以通过修改MySQL配置文件永久生效:
也可以在需要的会话中临时设置:transaction-isolation = SERIALIZABLESET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;。该方案的缺点是并发性能下降明显,仅适合并发量极低的场景。 - 手动加行锁:如果只是部分业务逻辑需要串行执行,可以在查询时加排他锁,例如
SELECT stock FROM goods WHERE id = 123 FOR UPDATE;,查询时就锁定目标行,后续的计算和UPDATE操作执行完成事务提交后才会释放锁,其余事务只能等待。 - 手动加表锁:如果需要整表级别的串行写入,可以执行
LOCK TABLES goods WRITE;锁定整个表,操作完成后执行UNLOCK TABLES;释放锁。该方案会阻塞所有针对该表的读写操作,并发性能极差,非特殊情况不推荐使用。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

