0

好的,这是不言自明的架构:

STORE(storeID, name, city)
PRODUCT(productID, name, brand)
PRODUCT_FOR_SALE(productID, storeID, price)

我有 2 笔交易:T1 和 T2
T1将在“伦敦”任何商店出售的任何产品的价格提高 5%。
T2将任何成本 >= 1050 美元的产品的价格降低 10%

我被要求告诉他们可能导致什么样的并发异常,以及我应该对哪个事务应用什么隔离级别以使其安全。

交易的代码没有给出,但我想它会是这样的:

# T1:
BEGIN;
    UPDATE product_for_sale 
    SET    price = price + ((price/100) *5)
    WHERE  storeID IN (SELECT storeID FROM store WHERE city='London')
COMMIT;

# T2:
BEGIN;
    UPDATE product_for_sale
    SET    price = price - (price/10)
    WHERE  price >= 1050
COMMIT;

READ COMMITTED我对(默认)可能发生的情况的“猜测”是:
考虑产品 P,在“伦敦”以 1049 美元的价格出售

  • 两笔交易开始
  • 他们都考虑他们的行集:T1 将考虑在伦敦销售的所有产品(包括 P),T2 将考虑价格为 1050 美元或更高的产品(不包括 P)
  • T1 提交并将 P 的价格设置为 1101 美元,但由于 P 不在 T2 开始时设置的行中,因此没有注意到更改,并且 T2 提交时没有考虑它

如果我没有弄乱定义,那应该是幻读的情况,如果我将 T2 设置为ISOLATION LEVEL REPEATABLE READ

4

1 回答 1

1

首先,您对并发问题的含义还不是很清楚。它可能是:

  1. 可以想象的问题,但由 PostgreSQL 自动处理,因此不会出现问题。

  2. 可能会产生意外错误或不良结果的东西。

对于 1.,这是由序列化尝试同时修改相同行的事务的锁来处理的。

我假设你对 2 更感兴趣。

您所描述的可能会发生,但这不是并发问题。它只是意味着 T1在逻辑上发生在 T2 之前。这在所有隔离级别上都可以正常工作。

我可能遗漏了一些东西,但我在这里看到的唯一潜在问题是两个语句之间的死锁:

它们都可以更新多行,因此它们中的一个可能会先更新 X 行,然后尝试更新 Y 行,而 Y 行已经被另一个语句更新了。然后第一个语句被阻止。现在第二条语句想要更新 Y 行,也被阻塞了。

这样的死锁在一秒钟后被死锁解析器通过终止出现错误的语句之一来打破。

请注意,死锁也不是真正的问题,您的代码所要做的就是重复失败的事务。

于 2019-09-05T11:02:16.723 回答