如何防止 Postgres 中的幻读?
How to prevent phantom reads in Postgres?
是否有可能防止幻读,或者以其他方式锁定 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' 的缺失。如何防止第二笔交易成功?
一种不锁定整个 table 的方法是使用 Postgresql 的 Advisory lock
[1] 机制:
-- tx 1
begin;
select pg_advisory_lock(1234);
insert/update....
commit;
-- tx 2
begin;
select pg_advisory_lock(1234);
SELECT * FROM weather WHERE city = 'a' FOR SHARE;
insert/update...
commit;
通过这种方式,您可以进行事务间通信,而普通的 MVCC 行为是不够的。在示例中 1234
是任意整数,具有应用程序级别的含义。另请参阅 [2] 了解更多使用咨询锁的方法。
[1] http://www.postgresql.org/docs/9.5/static/explicit-locking.html#ADVISORY-LOCKS
[2] http://www.postgresql.org/docs/9.5/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS-TABLE
是否有可能防止幻读,或者以其他方式锁定 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' 的缺失。如何防止第二笔交易成功?
一种不锁定整个 table 的方法是使用 Postgresql 的 Advisory lock
[1] 机制:
-- tx 1
begin;
select pg_advisory_lock(1234);
insert/update....
commit;
-- tx 2
begin;
select pg_advisory_lock(1234);
SELECT * FROM weather WHERE city = 'a' FOR SHARE;
insert/update...
commit;
通过这种方式,您可以进行事务间通信,而普通的 MVCC 行为是不够的。在示例中 1234
是任意整数,具有应用程序级别的含义。另请参阅 [2] 了解更多使用咨询锁的方法。
[1] http://www.postgresql.org/docs/9.5/static/explicit-locking.html#ADVISORY-LOCKS
[2] http://www.postgresql.org/docs/9.5/static/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS-TABLE