此 PostgreSQL 代码会造成哪些并发问题?
What concurrency issues can this PostgreSQL code create?
好的,这是不言自明的模式:
STORE(storeID, name, city)
PRODUCT(productID, name, brand)
PRODUCT_FOR_SALE(productID, storeID, price)
我有 2 笔交易:T1 和 T2。
T1
将 'London' 的任何商店中销售的任何产品的价格提高 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;
我的 "guess" 到 READ COMMITTED
(默认)可能发生的情况是:
考虑一个产品 P,在 'London' 以 1049 美元
的价格售出
- 两笔交易开始
- 他们都考虑他们的行集:T1 将考虑在伦敦销售的所有产品(包括 P),T2 将考虑价格为 1050 美元或以上的产品(不包括 P)
- T1 提交并将 P 的价格设置为 1101 美元,但是由于 P 不在 T2 的行集合中,因此更改未被注意到,T2 提交时没有考虑它
如果我没有弄乱定义,应该是幻读的情况,如果我将 T2 设置为 ISOLATION LEVEL REPEATABLE READ
,这将得到修复
首先,您对并发问题的含义不是很清楚。可能是:
可能是个问题,但由 PostgreSQL 自动处理,因此不会出现问题。
可能会产生意外错误或不良结果的东西。
对于 1.,这是由序列化试图同时修改相同行的事务的锁处理的。
我猜你对 2 更感兴趣。
你描述的情况可能会发生,但这不是并发问题。这只是意味着 T1 逻辑上 发生在 T2 之前。这将适用于所有隔离级别。
我可能遗漏了一些东西,但我在这里看到的唯一潜在问题是两个语句之间的死锁:
它们都可以更新多行,因此可能会发生其中一个先更新行 X,然后尝试更新行 Y,而该行已被另一个语句更新。第一个语句然后被阻止。现在第二条语句想要更新 Y 行也被阻塞了。
这样的死锁在一秒后被死锁解决程序打破,方法是杀死其中一个有错误的语句。
请注意,死锁也不是真正的问题,您的代码所要做的就是重复失败的事务。
好的,这是不言自明的模式:
STORE(storeID, name, city)
PRODUCT(productID, name, brand)
PRODUCT_FOR_SALE(productID, storeID, price)
我有 2 笔交易:T1 和 T2。
T1
将 'London' 的任何商店中销售的任何产品的价格提高 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;
我的 "guess" 到 READ COMMITTED
(默认)可能发生的情况是:
考虑一个产品 P,在 'London' 以 1049 美元
- 两笔交易开始
- 他们都考虑他们的行集:T1 将考虑在伦敦销售的所有产品(包括 P),T2 将考虑价格为 1050 美元或以上的产品(不包括 P)
- T1 提交并将 P 的价格设置为 1101 美元,但是由于 P 不在 T2 的行集合中,因此更改未被注意到,T2 提交时没有考虑它
如果我没有弄乱定义,应该是幻读的情况,如果我将 T2 设置为 ISOLATION LEVEL REPEATABLE READ
首先,您对并发问题的含义不是很清楚。可能是:
可能是个问题,但由 PostgreSQL 自动处理,因此不会出现问题。
可能会产生意外错误或不良结果的东西。
对于 1.,这是由序列化试图同时修改相同行的事务的锁处理的。
我猜你对 2 更感兴趣。
你描述的情况可能会发生,但这不是并发问题。这只是意味着 T1 逻辑上 发生在 T2 之前。这将适用于所有隔离级别。
我可能遗漏了一些东西,但我在这里看到的唯一潜在问题是两个语句之间的死锁:
它们都可以更新多行,因此可能会发生其中一个先更新行 X,然后尝试更新行 Y,而该行已被另一个语句更新。第一个语句然后被阻止。现在第二条语句想要更新 Y 行也被阻塞了。
这样的死锁在一秒后被死锁解决程序打破,方法是杀死其中一个有错误的语句。
请注意,死锁也不是真正的问题,您的代码所要做的就是重复失败的事务。