33.8. 异步提示
PostgreSQL通过LISTEN
和NOTIFY
命令提供了异步通知。一个客户端会话用LISTEN
命令在一个特定的通知频道中注册它感兴趣的通知(也可以用UNLISTEN
命令停止监听)。当任何会话执行一个带有特定频道名的NOTIFY
命令时,所有正在监听该频道的会话会被异步通知。可以传递一个“载荷”字符串来与监听者沟通附加的数据。
libpq应用把LISTEN
、UNLISTEN
和NOTIFY
命令作为通常的 SQL 命令提交。 随后通过调用PQnotifies
来检测NOTIFY
消息的到达。
函数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
域并不代表独立分配的内存(这些域的名称是历史性的,尤其是频道名称与关系名称没有什么联系)。
例 33.2给出了一个例子程序展示异步通知的使用。
PQnotifies
实际上并不从服务器读取数据;它只是返回被另一个libpq函数之前吸收的消息。在以前的libpq版本中,及时收到NOTIFY
消息的唯一方法是持续地提交命令,即使是空命令也可以,并且在每次PQexec
后检查PQnotifies
。 虽然这个方法还能用,但是由于太过浪费处理能力已被废弃。
当你没有可用的命令提交时,一种更好的检查NOTIFY
消息的方法是调用PQconsumeInput
,然后检查PQnotifies
。你可以使用select()
来等待服务器数据到达,这样在无事可做时可以不浪费CPU能力(参考PQsocket
来获得用于select()
的文件描述符)。注意不管是用PQsendQuery
/PQgetResult
提交命令还是简单地使用PQexec
,这种方法都能正常工作。不过,你应该记住在每次PQgetResult
或PQexec
之后检查PQnotifies
,看看在命令的处理过程中是否有通知到达。