首页 > 解决方案 > 可序列化隔离级别混淆 - 写入偏差 (Postgres)

问题描述

我正在运行 Postgres12 并对可序列化事务级别的行为感到困惑。

表:

活动

  1. ID
  2. 困难

经理人

  1. ID
  2. 等级

预期行为(在序列化事务中):

  1. 检查是否有 7 个或更多难度=2 的事件
  2. 如果是这样,请插入 level=2 的经理

我正在以可序列化的方式运行以下事务,但没有看到预期的行为(期望可序列化事务检测 2 个会话之间的写入偏差)

-- session 1:
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE
SELECT count(*) from events WHERE difficulty=2
-- RETURNS 7
-- now start session 2
-- session 2:
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE
SELECT id FROM events WHERE difficulty=2 LIMIT 1;
/* 
 id 
----
  4
*/
 UPDATE events SET difficulty=1 WHERE id=4;
COMMIT;

现在只有 6 个难度事件=2

-- back in session 1
-- since we have counted 7 events of difficulty=2 in this session, create a manager
INSERT INTO manager (level) VALUES (2);
COMMIT;
-- Expected write skew to be detected here bc the read event rows have seen updates (only 6 actually)

不幸的是,我们的最终状态现在是 6 个难度 = 2 的事件和一个级别 2 的管理器。 为什么可序列化隔离不能防止这种写入倾斜? 我对可序列化隔离用例有什么误解?为什么难度=2 的事件没有被谓词锁定或某种隔离机制锁定或监视?

为清晰起见图片 在此处输入图像描述

标签: postgresqlisolation-leveltransaction-isolation

解决方案


SERIALIZABLE意味着有一种方法可以顺序执行事务(一个接一个),这样效果是一样的。在您的情况下,这个等效的串行执行将首先运行会话 1,然后运行会话 2,效果相同。

您可以说会话 1 在会话 2 之前“逻辑地”执行。


推荐阅读