在我使用 Postgresql 的应用程序中,订购产品过程可能会导致竞争条件。让我描述一下我的案例。我的数据库中有三个表:
Id string
Quantity int
Id string
Name string
Id string
UserId string
ProductId string
Quantity int
在这个过程中,我分两个阶段来完成。我从产品表中读取以检查“产品是否可用”如果房间不可用,我会向用户回复一条错误消息;另一方面,我会为订购表创建一条记录,并向用户发送一条响应成功消息。
这是处理该问题的sql:
--- get quantity from product id
SELECT quantity
FROM Product
WHERE id = '456';
--- if the product's quantity is greater than the ordering quantity then
UPDATE Product
SET quantity = quantity - 1
WHERE id = '456';
INSERT INTO Ordering (id, user_id, product_id, quantity)
VALUES ('1', '123', '456', 1);
--- else I would respond to customer error response
但是我意识到这个过程可能会导致竞争条件。然后我找到了一个想法来解决它。我在产品和订购表中创建了一个名为 version 的字段。我在检查可用产品时更新版本。但我对这个解决方案有疑问。
SQL 将变为如下:
--- get quantity from product id
SELECT quantity
FROM Product
WHERE id = '456' and version = 1;
--- if the product's quantity is greater than the ordering quantity then
UPDATE Product
SET quantity = quantity - 1, version = version + 1
WHERE id = '456' and version = 1;
INSERT INTO Ordering (id, user_id, product_id, quantity, version)
VALUES ('1', '123', '456', 1, 1);
--- else I would respond to the customer error response
如果产品的数量是99,并且我同时有100个客户购买产品的请求。在这种情况下,只有一位客户订购成功,另一位客户订购失败。但我预计有 99 人下单成功,只有 1 名客户下单失败。
有人可以给我一些关于这个问题的建议吗?我花了很长时间来考虑。感谢您的关注。
您面临的问题确实是数据库中竞争条件的典型示例。在您的场景中,多个请求尝试同时更新产品数量,这可能会导致意外结果。使用版本字段来处理并发控制是朝着正确方向迈出的一步,但似乎并不能完全解决问题。
为了更有效地处理这种情况,您可以使用一个称为“乐观并发控制”的概念。以下是实施方法:
向您的产品表添加版本列:
ALTER TABLE Product
ADD COLUMN version integer DEFAULT 0;
修改您的 SQL 查询:
-- get quantity and version from product id
SELECT quantity, version
FROM Product
WHERE id = '456';
-- if the product's quantity is greater than the ordering quantity and version matches
UPDATE Product
SET quantity = quantity - 1, version = version + 1
WHERE id = '456' AND version = 1;
-- Check the number of rows affected by the update query.
-- If it's 0, then the version mismatch occurred, and the operation should be rolled back.
-- If it's 1, the update was successful.
-- Handle this logic in your application code.
-- If the update was successful, insert into Ordering table.
处理应用程序代码中的并发冲突: 在您的应用程序中,执行更新查询后,检查有多少行受到影响。如果更新影响了 0 行,则意味着自您上次读取该行以来,另一个事务已经更新了该行。在这种情况下,您可以通过重试整个过程或通知用户该产品不再可用来处理冲突。
通过实施乐观并发控制,您可以允许多个事务独立进行,除非存在冲突(即并发修改相同数据)。当发生冲突时,您的应用程序可以检测到并进行适当处理,确保您的订购过程既安全又高效。