【发布时间】:2016-04-03 18:44:58
【问题描述】:
是否可以防止幻读,或者锁定 Postgres 事务中丢失的行?例如,考虑以下命令序列:
在连接 1 上:
CREATE TABLE weather ( city varchar(80) PRIMARY KEY );
BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
INSERT INTO weather VALUES ('a');
同时,在连接 2 上:
BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT * FROM weather WHERE city = 'a' FOR SHARE;
INSERT INTO weather VALUES ('b');
然后回到连接 1:
COMMIT;
再次回到连接 2:
COMMIT;
SELECT * FROM weather;
-- Shows both rows
连接 2 上的事务似乎不可能成功,因为创建“b”行的前提条件取决于“a”行的缺失。如何防止第二笔交易成功?
【问题讨论】:
-
psql (PostgreSQL) 9.3.11
-
可序列化事务只要行为与这些事务的 some 串行顺序一致就可以成功,但这种排序与这些事务的顺序无关已启动或已提交。在这种情况下,如果您先运行事务 2,然后运行事务 1,您似乎会得到相同的结果,所以我看不出有任何冲突的原因。
-
确实如此,尽管它并没有让我更接近问题的答案。如何在不锁定整个数据库或表的情况下进行原子读写?
-
当您说“幻读”时,您是指
SELECT * FROM weather看到行'a'的事实吗?如果它们不在同一个事务块中,则无法保证此SELECT与之前的SELECT之间的一致性。 -
就像我说的,提交的实际顺序是无关紧要的。数据库“假装”#2 首先发生,并且它能够这样做是因为没有会话观察到任何与此事件序列不一致的行为。如果您在两次提交之间有第三个可序列化事务运行
SELECT * FROM weather,它将看到a,而不是b;这将排除 #2 先出现的可能性,并且 #2 在提交时会失败。