PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

32.9. 异步通知处理 #

PostgreSQL 通过 LISTEN 和 NOTIFY 命令提供异步通知。 一个客户端会话用 LISTEN 命令注册它对某个特定通知渠道的兴趣 (并且可以用 UNLISTEN 命令停止监听)。 当任何会话执行了一条带有该渠道名的 NOTIFY 命令时, 所有在该特定渠道上监听的会话都会被异步通知。 可以传递一个 “载荷”字符串, 向监听者传达额外的数据。

libpq 应用程序把 LISTEN、 UNLISTEN 和 NOTIFY 命令作为普通的 SQL 命令提交。 NOTIFY 消息的到达随后可以通过调用 PQnotifies 来检测。

函数 PQnotifies 从从服务器收到的、未被处理的通知消息列表中返回下一条通知。 如果没有待处理的通知, 它返回一个空指针。 一旦一条通知从 PQnotifies 返回, 它就被视为已被处理, 并且会从通知列表中被移除。

PGnotify *PQnotifies(PGconn *conn);

typedef struct pgNotify
{
    char *relname;              /* notification channel name */
    int  be_pid;                /* process ID of notifying server process */
    char *extra;                /* notification payload string */
} PGnotify;

在处理完 PQnotifies 返回的一个 PGnotify 对象之后, 请确保用 PQfreemem 释放它。 释放 PGnotify 指针就足够了; relname 和 extra 字段并不代表单独的分配。 (这些字段的名字是历史上的; 特别是渠道名字与关系名字没有任何必然联系。)

Example 32.2 给出了一个演示异步通知使用的示例程序。

PQnotifies 实际上并不从服务器读取数据; 它只是返回先前被另一个 libpq 函数吸收的消息。 在 libpq 的古老发行版中, 确保及时收到 NOTIFY 消息的唯一方式是不断提交命令, 甚至是空命令, 然后在每次 PQexec 之后检查 PQnotifies。 虽然这样做仍然可行, 但它作为对处理能力的浪费已被弃用。

当你没有什么有用的命令可执行时, 一种更好的检查 NOTIFY 消息的方式是调用 PQconsumeInput , 然后检查 PQnotifies。 你可以使用 select() 来等待来自服务器的数据到达, 从而在没有事情可做时不消耗任何 CPU 能力。 (参见 PQsocket 来获得与 select() 一起使用的文件描述符编号。) 注意, 无论你是用 PQsendQuery/PQgetResult 提交命令, 还是简单地使用 PQexec, 这样做都能正常工作。 不过, 你应当记得在每次 PQgetResult 或 PQexec 之后检查 PQnotifies, 看看在命令处理期间是否有任何通知进来。