27.6. 異步通知

PostgreSQL 通過LISTENNOTIFY命令提供對異步通知的支持。 一個服務器用LISTEN命令注冊一個它感興趣的通知條件 (也可以用UNLISTEN命令停止監聽)。 所有正在監聽某一通知條件的會話在該條件名的 NOTIFY(通知)被任何會話執行後都將被異步地通知。 通知發出者不會傳遞附加的信息到監聽者。因此,很典型地是, 任何實際的需要被傳遞的數據都是通過一個數據庫表傳遞的。 通常,條件名與相關聯的表同名,但是並不是一定要與某個表相關才行。

libpq 應用把LISTENUNLISTEN 命令作為通常的 SQL 命令提交。 隨後通過調用PQnotifies()可以偵測到 NOTIFY 消息的到達。

函數PQnotifies 從一個來自服務器的未處理的通知信息列表中返回下一條通知。 如果沒有未處理的信息則返回 NULL 指針。 一旦PQnotifies返回一條通知, 該通知會被認為已處理並且將被從通知列表中刪除。

PGnotify* PQnotifies(PGconn *conn);

typedef struct pgNotify {
    char *relname;		   /* 通知名字*/
    int  be_pid;		   /* 服務器進程 id*/
    char *extra;                /* 通知參數 */
} PGnotify;

在處理完 PQnotifies 返回的PGnotify對象後, 別忘了用PQfreemem() 把它釋放,以避免內存洩漏。 釋放 PGnotify 指針就足夠了;relnameextra 字段並未代表獨立分配的內存。(目前,extra 字段沒有使用, 並且將總是指向一個空字串。)

注意: PostgreSQL 6.4 和更高的版本裡, be_pid 是正在通知的服務器的 PID, 而在早些的版本裡它總是你自己的服務器的PID

Example 27-2 給出了一個使用異步通知的例子。

PQnotifies() 實際上並不讀取服務器數據; 它只是返回被前面的另一個libpq函數吸收的信息。 在以前的 libpq 的版本裡, 週期性的收到NOTIFY信息的唯一方法是持續的提交命令, 即使是空查詢也可以,並且在每次 PQexec()後檢查 PQnotifies() 。現在這個方法也能還工作, 不過我們認為它太浪費處理器時間而廢棄了它。

在你沒有可用的命令提交時檢查NOTIFY消息的更好的方法是調用 PQconsumeInput(),然後檢查 PQnotifies()。你可以使用 select() 來等待服務器數據的到達, 這樣在沒有數據可處理時可以不浪費 CPU 時間。 (參閱PQsocket() 獲取用于 select()的文件描述符。) 注意這種方法不管你使用 PQsendQuery/PQgetResult 還是簡單的 PQexec來執行命令都能工作。不過,你應該記住在每次 PQgetResultPQexec後檢查 PQnotifies() ,看看在處理命令的過程中是否有通知到達。