冲突的交易导致奇怪的行为

问题描述 投票:0回答: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
mysql transactions
1个回答
1
投票

inventory的更新中,我们可以对值进行调整,而不是指定替换值

((我们将假设此问题不是针对transaction_log表的INSERT问题;向该表添加行可以正常工作。我们将假定问题与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值),然后将零存储为现有数量,这可能不是我们想要的。

© www.soinside.com 2019 - 2024. All rights reserved.