我有一个记录销售交易的应用程序。在此过程中,库存金额将更新并记录。这些查询作为事务运行。但是,如果其中两个事务同时运行,那么;库存数量和日志记录可能不正确。
下面是查询的示例。如果它们在同一时间运行,则第二个查询可能会看到与第一个查询所看到的值相同的值,从而导致只有一笔交易正确地更新了数量。事务日志将同时具有两个条目,但是如果同时运行,则当前数量将是错误的。
确保这些事务以不会引起不一致的方式运行的最佳方法是什么
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
表的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值),然后将零存储为现有数量,这可能不是我们想要的。