【问题标题】:What concurrency issues can this PostgreSQL code create?此 PostgreSQL 代码会产生哪些并发问题?
【发布时间】:2019-09-05 10:36:39
【问题描述】:

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

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;

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

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

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

【问题讨论】:

    标签: postgresql concurrency transactions isolation repeatable-read


    【解决方案1】:

    首先,您对并发问题的意思不是很清楚。可能是:

    1. 可能是问题,但由 PostgreSQL 自动处理,因此不会出现问题。

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

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

    我假设你对 2 更感兴趣。

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

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

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

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

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

    【讨论】:

    • 并发问题是指脏读、不可重复读、幻读或序列化异常。一般来说,任何会导致命令产生意想不到的结果的东西我的教授在过去的几次考试中都提出了这个问题,我就是无法理解它。我猜他希望得到一些答案,例如“这可能发生在 READ COMMITTED 中,将此事务设置为此隔离级别会解决这个问题”,但我找不到比问题正文中的解释更好的解释,这类似于postgres 文档中提供的示例
    • 在 PostgreSQL 中,无论序列化级别如何,这两条语句都不会导致序列化异常发生。如果您认为死锁是一种序列化异常,那么这就是可能发生的情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-03
    • 1970-01-01
    • 1970-01-01
    • 2016-03-29
    • 1970-01-01
    相关资源
    最近更新 更多