MySQL 事务及数据的一致性处理

warning: 这篇文章距离上次修改已过793天,其中的内容可能已经有所变动。

在工作中,我们经常会遇到这样的问题,需要更新库存,当我们查询到可用的库存准备修改时,这时,其他的用户可能已经对这个库存数据进行修改了,导致,我们查询到的数据会有问题,下面我们就来看解决方法。

如果SELECT 后面若要UPDATE 同一个表单,最好使用SELECT ... UPDATE。

举个例子

假设商品表单 products 内有一个存放商品数量的 quantity,在订单成立之前必须先确定 quantity 商品数量是否足够( quantity > 0 ),然后才把数量更新为 1 。

SELECT quantity FROM products WHERE id = 3; UPDATE products SET quantity = 1 WHERE id = 3;

开启事务

为什么不安全呢?

高并发时会出现问题,如果我们需要在 quantity > 0 的情况下才能扣库存,假设程序在第一行 SELECT 读到的 quantity 是 2,但是当 MySQL 正准备要 UPDATE 的时候,可能已经有人把库存扣成 0 了,但是程序却浑然不知,将错就错的 UPDATE 下去了。因此必须利用事务机制来确保读取及提交的数据都是正确的。

BEGIN WORK; SELECT quantity FROM products WHERE id = 3 FOR UPDATE;

此时 products 数据中 id = 3 的数据被锁住,其它事务必须等待此次事务提交后才能执行。

SELECT * FROM products WHERE id = 3 FOR UPDATE;

确保 quantity 在事务中读取的数据是可靠的。

UPDATE products SET quantity = '1' WHERE id = 3; COMMIT WORK;

提交 (Commit) 事务,products 解锁。

Tips:

  1. BEGIN / COMMIT 为事务的起始及结束点;
  2. 在事务进行当中,只有 SELECT ... FOR UPDATELOCK IN SHARE MODE 会等待事务结束后才执行,一般的 SELECT ... 则不受此影响。

简单用法

为了防止处理不当,根据业务实际情况,如果我们需要先查询,后更新数据的话,可以这样使用语句:

UPDATE products SET quantity = '1' WHERE id = 3 AND quantity > 0;
最后修改于:2022年05月05日 05:56

添加新评论