Postgresql 中文操作指南

34.9. Asynchronous Notification #

PostgreSQL 通过 LISTENNOTIFY 命令提供异步通知。客户端会话通过 LISTEN 命令在特定通知频道中注册对其的兴趣(并且可以使用 UNLISTEN 命令停止侦听)。当任何会话通过带有该频道名称的 NOTIFY 命令执行一个通知时,侦听特定频道的会话将异步收到通知。可以传递一个“载荷”字符串,向侦听器传达其他数据。

PostgreSQL offers asynchronous notification via the LISTEN and NOTIFY commands. A client session registers its interest in a particular notification channel with the LISTEN command (and can stop listening with the UNLISTEN command). All sessions listening on a particular channel will be notified asynchronously when a NOTIFY command with that channel name is executed by any session. A “payload” string can be passed to communicate additional data to the listeners.

libpq 应用程序将 LISTENUNLISTENNOTIFY 命令作为常规 SQL 命令提交。随后可以通过调用 PQnotifies 来检测到 NOTIFY 消息的到达。

libpq applications submit LISTEN, UNLISTEN, and NOTIFY commands as ordinary SQL commands. The arrival of NOTIFY messages can subsequently be detected by calling PQnotifies.

函数 PQnotifies 从服务器处接收到的一系列未处理的通知消息中返回下一个通知。如果没有待定的通知,它会返回一个空指针。一旦从 PQnotifies 返回一个通知,将认为它已处理并从通知列表中删除。

The function PQnotifies returns the next notification from a list of unhandled notification messages received from the server. It returns a null pointer if there are no pending notifications. Once a notification is returned from PQnotifies, it is considered handled and will be removed from the list of notifications.

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 指针就足够了; relnameextra 字段不表示单独分配。(这些字段的名称是有历史意义的;特别是,通道名称不必与关系名称有任何关系。)

After processing a PGnotify object returned by PQnotifies, be sure to free it with PQfreemem. It is sufficient to free the PGnotify pointer; the relname and extra fields do not represent separate allocations. (The names of these fields are historical; in particular, channel names need not have anything to do with relation names.)

Example 34.2 提供了一个示例程序,说明了异步通知的使用。

Example 34.2 gives a sample program that illustrates the use of asynchronous notification.

PQnotifies 并不实际从服务器读取数据;它仅仅返回先前由另一个 libpq 函数吸收的消息。在 libpq 的旧版本中,确保及时收到 NOTIFY 消息的唯一方法是不断提交命令,即使是空命令,然后在每个 PQexec 后检查 PQnotifies 。虽然此方法仍然适用,但已弃用,因为它会浪费处理能力。

PQnotifies does not actually read data from the server; it just returns messages previously absorbed by another libpq function. In ancient releases of libpq, the only way to ensure timely receipt of NOTIFY messages was to constantly submit commands, even empty ones, and then check PQnotifies after each PQexec. While this still works, it is deprecated as a waste of processing power.

当没有要执行的有用命令时,检查 NOTIFY 消息的更好的方法是调用 PQconsumeInput ,然后检查 PQnotifies 。你可以使用 select() 等待数据从服务器到达,从而在没有事情要做时不使用任何 CPU 能力。(请参见 PQsocket 以获取在 select() 中使用的文件描述符数量。)请注意,无论你用 PQsendQuery / PQgetResult 提交命令,还是仅仅使用 PQexec ,这都适用。但是,在每次 PQgetResultPQexec 后,你都应记得检查 PQnotifies ,以查看在处理命令期间是否收到了任何通知。

A better way to check for NOTIFY messages when you have no useful commands to execute is to call PQconsumeInput , then check PQnotifies. You can use select() to wait for data to arrive from the server, thereby using no CPU power unless there is something to do. (See PQsocket to obtain the file descriptor number to use with select().) Note that this will work OK whether you submit commands with PQsendQuery/PQgetResult or simply use PQexec. You should, however, remember to check PQnotifies after each PQgetResult or PQexec, to see if any notifications came in during the processing of the command.