27.7. 異步通知

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() ,看看在處理命令的過程中是否有通知到達。