mysql - 冲突的交易导致奇怪的行为
问题描述
我有一个记录销售交易的应用程序。在此过程中,会更新和记录库存量。这些查询作为事务运行。但是,如果其中 2 个事务同时运行;库存计数和记录可能不正确。
下面是一个查询示例。如果它们同时运行,第二个查询可能会看到与第一个查询相同的值,导致只有 1 个事务来正确更新数量。事务日志将包含两个条目,但如果它们同时运行,当前数量将是错误的。
确保这些事务以不会导致不一致的方式运行的最佳方法是什么
INSERT INTO transaction_log(item_id, current_quantity, amount_changed) VALUES (1, 10,-1);
INSERT INTO inventory (current_quantity, item_id) VALUES (10, 1) ON DUPLICATE KEY UPDATE quantity = 10
解决方案
在 的更新中inventory
,我们可以对值进行调整,而不是指定替换值
(我们假设这个问题不是指插入transaction_log
表的问题;向该表添加行可以正常工作。我们假设问题在于inventory
表的更新)
我们将假设current_quantity
列列表中引用的列是来自交易的数量,而quantity
更新部分中引用的列是运行值。
为了这个例子,我将把它们称为数量“调整”和“现有”。
假设表格行当前如下所示:
item_id quantity_onhand quantity_adjust
------- --------------- ---------------
1 100 20
当前的现有库存为 100,最后应用的调整为 20。
假设我们需要调整quantity_onhand
10 的值。我们可以这样做:
INSERT INTO inventory (item_id, quantity_adjust) VALUES (1, 10)
ON DUPLICATE KEY
UPDATE quantity_onhand = quantity_onhand + VALUES(quantity_adjust)
, quantity_adjust = VALUES(quantity_adjust)
假设 item_id 是插入违反的主键(或唯一键),我们期望结果是:
item_id quantity_onhand quantity_adjust
------- --------------- ---------------
1 110 10
即,将 10 添加到“现有”数量,并将 10 存储为最后一个“调整”值。
请注意,在语句的更新部分VALUES()
,如果插入成功,该函数将返回将被插入的值。
结果实际上等同于执行以下语句:
UPDATE inventory
SET quantity_onhand = quantity_onhand + 10
, quantity_adjust = 10
WHERE item_id = 1
因为该语句只提供一个调整值,而不是一个特定的现有值,即从行本身获取当前库存值,所以在该行被语句锁定时,这会处理多个语句尝试替换的并发问题现有库存量。
请注意,我们还需要处理INSERT
语句成功、行不存在的情况。我们可以将该quantity_onhand
列定义为 `DEFAULT 0(以避免存储 NULL 值),然后我们会得到一个存储为现有量的零,这可能不是我们想要的。
推荐阅读
- php - 保存内容后更改时区
- unity3d - 使用 Addressables 时精灵显示不正确
- azure - 自定义图形连接器中的 Azure AD 标识映射
- webpack - 如何强制 vue/webpack 在别名文件夹上使用与源根目录相同的 linter
- sql - 重叠生效日期聚合
- slatejs - Slatejs editor.selection 在弹出框上返回 null?
- c - 仅包含字符的结构是否无填充?
- c++ - 将 winusb dll 添加到代码块
- powershell - Powershell 脚本不写正确的变音符号 - Powershell 本身可以
- javascript - 在Javascript中获取“输入意外结束”