取决于您要完成的工作。
如果您需要一个简单的数字来描述产品的可用数量,只需将其作为字段存储在产品表中即可。在单个语句中更新它是原子的:
UPDATE PRODUCT
SET AMOUNT = AMOUNT + <change>
WHERE PRODUCT_ID = <whatever>
或者,您可以执行以下操作:
START TRANSACTION;
SELECT AMOUNT
FROM PRODUCT
WHERE PRODUCT_ID = <whatever>
FOR UPDATE;
(Calculate new amount.)
UPDATE PRODUCT
SET AMOUNT = <new amount>
WHERE PRODUCT_ID = <whatever>;
COMMIT;
请注意 FOR UPDATE 锁定行直到 COMMIT 并防止在并发环境中可能出现的异常。
如果没有 FOR UPDATE,仅仅常规的 ACID 保证是不够的。例如:
- 事务A选择当前的 AMOUNT,假设它是 5。
- 事务B选择当前的 AMOUNT,它仍然是 5,因为还没有其他事务提交任何更改。
- 交易A将金额加 2,结果为 7。
- 交易B将金额加 3,结果为 8。
- 事务A将该行更新为 7 并提交。
- 事务B将该行更新为 8 并提交。
突然,表格中的结果 AMOUNT 为 5 + 3 = 8,即使它本应为 5 + 2 + 3 = 10。其中一个更改丢失了 - 最后提交的人获胜。
如果您需要产品数量的历史记录,或者需要跟踪产品的单个“实例”,那么是的,您需要一个 1:N 关系中的单独表,这在并发环境中可能有自己的锁定挑战。
库存量为非负值。
不幸的是,MySQL 不强制执行 CHECK 约束,但对于这种特定情况,您可以简单地使用一种UNSIGNED数据类型。