34.9. 异步通知#
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
字段并不表示单独的分配。(这些字段的名称是历史性的;特别是,频道名称不必与关系名称有任何关系。)
示例 34.2提供了一个示例程序,说明了异步通知的使用。
PQnotifies
实际上不会从服务器读取数据;它仅返回之前由另一个libpq函数吸收的消息。在libpq的旧版本中,确保及时收到NOTIFY
消息的唯一方法是不断提交命令,即使是空命令,然后在每次PQexec
后检查PQnotifies
。虽然此方法仍然有效,但它已被弃用,因为它会浪费处理能力。
当您没有要执行的有用命令时,检查NOTIFY
消息的更好方法是调用PQconsumeInput
,然后检查PQnotifies
。您可以使用select()
等待数据从服务器到达,从而在没有事情可做时不使用CPU能力。(请参阅PQsocket
以获取与select()
一起使用的文件描述符编号。)请注意,无论您使用PQsendQuery
/PQgetResult
提交命令,还是仅仅使用PQexec
,此方法都适用。然而,您应该记住在每次PQgetResult
或PQexec
后检查PQnotifies
,以查看在处理命令期间是否收到任何通知。