31.7. 异步通知

PostgreSQL通过LISTENNOTIFY命令提供对异步通知的支持。 一个服务器用LISTEN命令注册一个它感兴趣的通知条件(也可以用UNLISTENcommand)命令停止监听)。 所有正在监听某一通知条件的会话在该条件名的NOTIFY(通知)被任何会话执 行后都将被异步地通知。通知发出者不会传递附加的信息到监听者。因此,很典型地是 ,任何实际的需要被传递的数据都是通过一个数据库表传递的。通常,条件名与相关联的表同名, 但是并不是一定要与某个表相关才行。一个"payload"可以向听众传达额外的数据。

libpq应用把LISTENUNLISTENNOTIFY命令作为通常的 SQL 命令提交。 随后通过调用,PQnotifies 可以侦测到NOTIFY消息的到达。

函数PQnotifies从一个来自服务器的未处理的通知信息列表中返回下一条通知。 如果没有未处理的信息则返回 NULL 指针。一旦PQnotifies返回一条通知, 该通知会被认为已处理并且将被从通知列表中删除。

PGnotify *PQnotifies(PGconn *conn);

typedef struct pgNotify
{
    char *relname;              /* notification channel name   通知名字*/
    int  be_pid;                /* process ID of notifying server process  服务器进程ID*/
    char *extra;                /* notification payload string   通知参数*/
} PGnotify;

在处理完PGnotify返回的PQnotifies对象后,别忘了用PQfreemem把它释放, 以避免内存泄漏。释放PGnotify指针就足够了;relnameextra字段并未代表独立分配的内存。 (这些领域的名称是历史性的,尤其是频道名称与名称没有什么关系。)

Example 31-2给出了一个使用异步通知的例子。

PQnotifies实际上并不读取服务器数据;它只是返回被前面的另 一个libpq函数吸收的信息。在以前的libpq的版本里,周期性的收到NOTIFY信息 的唯一方法是持续的提交命令,即使是空查询也可以,并且在每次PQexec后检查PQnotifies。 现在这个方法也能还工作,不过我们认为它太浪费处理器时间而废弃了它。

在你没有可用的命令提交时检查NOTIFY消息的更好的方法是调用PQconsumeInput, 然后检查PQnotifies。你可以使用select()来等待服务器数据的到达, 这样在没有数据可处理时可以不浪费CPU时间。(参阅PQsocket获取 用于select()的文件描述符。)注意这种方法不管你使用PQsendQuery/PQgetResult 还是简单的PQexec.来执行命令都能工作。不过,你应该记住在每次PQgetResult或 PQexec后检查PQexec,看看在处理命令的过程中是否有通知到达。