Postgres 通知不会自动到达
Postgres notifications not arriving automatically
我在一个终端A中打开psql
(ArchLinux上的PostgreSQL 9.5.4)并发出LISTEN "notif";
在另一个终端B,然后我运行下面的脚本(psql -f myscript.sql
).
这将创建一个带有两个触发器的 table。如果在 send
为 TRUE 的位置添加了一行,则一个触发器会触发;如果更新了一行,使得 send
从 FALSE 变为 TRUE,则会触发另一个触发器。两个触发器都发送通知。
DROP TRIGGER IF EXISTS do_notif ON notif;
DROP TRIGGER IF EXISTS do_notif2 ON notif;
DROP TABLE IF EXISTS notif;
CREATE TABLE notif (id INT PRIMARY KEY, send BOOLEAN, msg TEXT);
CREATE OR REPLACE FUNCTION post() RETURNS TRIGGER AS $$
BEGIN
PERFORM pg_notify('notif', '+' || NEW.id::TEXT || ',' || coalesce(NEW.msg, '(null)'));
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION post2() RETURNS TRIGGER AS $$
BEGIN
PERFORM pg_notify('notif', '~' || NEW.id::TEXT || ',' || coalesce(NEW.msg, '(null)'));
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER do_notif AFTER INSERT ON notif
FOR EACH ROW WHEN (NEW.send)
EXECUTE PROCEDURE post();
CREATE TRIGGER do_notif2 AFTER UPDATE OF send ON notif
FOR EACH ROW WHEN (NEW.send AND NOT OLD.send)
EXECUTE PROCEDURE post2();
-- LISTEN "notif";
INSERT INTO notif VALUES (1, FALSE, 'update');
INSERT INTO notif VALUES (2, TRUE, 'insert');
UPDATE notif SET send = TRUE;
UPDATE notif SET send = FALSE;
UPDATE notif SET send = TRUE;
START TRANSACTION;
INSERT INTO notif VALUES (10, FALSE, 'a'), (11, TRUE, 'b'), (12, TRUE, 'c');
UPDATE notif SET send = TRUE WHERE id = 10;
COMMIT
我希望相关的 INSERT 和 UPDATE 查询会导致触发器被调用,发送通知,终端 A.
这不会发生。我必须在终端 A 中再次手动 运行 LISTEN "notif";
,这会立即给我丢失的通知。
如果我取消注释该脚本中的 LISTEN "notif";
,那么 psql
实例 运行 脚本 (B) 将在相关位置向终端写入通知(在将 send
设置为 TRUE 的非事务性 insert/update 之后,以及事务之后)。
但是 A 仍然不显示这些,除非我在 运行 LISTEN "notif";
中再次 A (或任何其他查询,例如 SELECT TRUE;
)。这不是一些终端缓冲问题,因为仅在 A 中按 ENTER 不会导致出现通知。
PostgreSQL 似乎不会立即跨不同连接或不同进程传递通知,但当侦听器与生成通知的进程相同时确实会立即传递。
psql 在每个命令后检查通知队列(更具体地说,在从服务器收到任何结果后)。所以你可以使用listen channel
一次,之后的每个命令都会检查是否有新的通知。
基于libpq.c标准库的程序以相同的方式运行,从服务器接收数据后用the function PQnotifies
检查通知队列。他们还有另一种可能。在特定时间没有与服务器通信的情况下,他们可以使用函数 PQconsumeInput
刷新通知队列。通过这种方式,他们以异步方式接收通知。驱动程序的通知支持当然可以在更高级别实现。
我在一个终端A中打开psql
(ArchLinux上的PostgreSQL 9.5.4)并发出LISTEN "notif";
在另一个终端B,然后我运行下面的脚本(psql -f myscript.sql
).
这将创建一个带有两个触发器的 table。如果在 send
为 TRUE 的位置添加了一行,则一个触发器会触发;如果更新了一行,使得 send
从 FALSE 变为 TRUE,则会触发另一个触发器。两个触发器都发送通知。
DROP TRIGGER IF EXISTS do_notif ON notif;
DROP TRIGGER IF EXISTS do_notif2 ON notif;
DROP TABLE IF EXISTS notif;
CREATE TABLE notif (id INT PRIMARY KEY, send BOOLEAN, msg TEXT);
CREATE OR REPLACE FUNCTION post() RETURNS TRIGGER AS $$
BEGIN
PERFORM pg_notify('notif', '+' || NEW.id::TEXT || ',' || coalesce(NEW.msg, '(null)'));
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION post2() RETURNS TRIGGER AS $$
BEGIN
PERFORM pg_notify('notif', '~' || NEW.id::TEXT || ',' || coalesce(NEW.msg, '(null)'));
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER do_notif AFTER INSERT ON notif
FOR EACH ROW WHEN (NEW.send)
EXECUTE PROCEDURE post();
CREATE TRIGGER do_notif2 AFTER UPDATE OF send ON notif
FOR EACH ROW WHEN (NEW.send AND NOT OLD.send)
EXECUTE PROCEDURE post2();
-- LISTEN "notif";
INSERT INTO notif VALUES (1, FALSE, 'update');
INSERT INTO notif VALUES (2, TRUE, 'insert');
UPDATE notif SET send = TRUE;
UPDATE notif SET send = FALSE;
UPDATE notif SET send = TRUE;
START TRANSACTION;
INSERT INTO notif VALUES (10, FALSE, 'a'), (11, TRUE, 'b'), (12, TRUE, 'c');
UPDATE notif SET send = TRUE WHERE id = 10;
COMMIT
我希望相关的 INSERT 和 UPDATE 查询会导致触发器被调用,发送通知,终端 A.
这不会发生。我必须在终端 A 中再次手动 运行 LISTEN "notif";
,这会立即给我丢失的通知。
如果我取消注释该脚本中的 LISTEN "notif";
,那么 psql
实例 运行 脚本 (B) 将在相关位置向终端写入通知(在将 send
设置为 TRUE 的非事务性 insert/update 之后,以及事务之后)。
但是 A 仍然不显示这些,除非我在 运行 LISTEN "notif";
中再次 A (或任何其他查询,例如 SELECT TRUE;
)。这不是一些终端缓冲问题,因为仅在 A 中按 ENTER 不会导致出现通知。
PostgreSQL 似乎不会立即跨不同连接或不同进程传递通知,但当侦听器与生成通知的进程相同时确实会立即传递。
psql 在每个命令后检查通知队列(更具体地说,在从服务器收到任何结果后)。所以你可以使用listen channel
一次,之后的每个命令都会检查是否有新的通知。
基于libpq.c标准库的程序以相同的方式运行,从服务器接收数据后用the function PQnotifies
检查通知队列。他们还有另一种可能。在特定时间没有与服务器通信的情况下,他们可以使用函数 PQconsumeInput
刷新通知队列。通过这种方式,他们以异步方式接收通知。驱动程序的通知支持当然可以在更高级别实现。