本文介紹了NOTIFY的文法、參數以及樣本等內容。
簡介
NOTIFY命令發送一個通知事件以及一個可選的“載荷”字串給每個正在監聽的用戶端應用,這些應用之前都在當前資料庫中為指定的頻道名執行過LISTEN channel。通知對所有使用者都可見。
NOTIFY為訪問同一個PolarDB資料庫的進程集合提供了一種簡單的進程間通訊機制。伴隨著通知可以發送一個載荷字串,通過使用資料庫中的表從通知者向監聽者傳遞額外的資料,也可以構建用於傳輸結構化資料的高層機制。
由一個通知事件傳遞給用戶端的資訊包括通知頻道名稱、發出通知的會話的伺服器處理序 PID 以及載荷字串,如果載荷字串沒有被指定則它為空白字串。
將在一個給定資料庫以及其他資料庫中使用的頻道名稱由資料庫設計者定義。通常,頻道名稱與資料庫中某個表的名稱相同,並且通知事件其實就意味著:“我改變了這個表,來看看改了什麼吧”。但是NOTIFY和LISTEN命令並未強制這樣的關聯。例如,一個資料庫設計者可以使用幾個不同的頻道名稱來標誌一個表上的不同種類的改變。另外,載荷字串可以被用於多種不同的情況。
當NOTIFY被用來標誌對一個特定表的改變時, 一種有用的編程技巧是把NOTIFY 放在一個由表更新觸發的語句觸發器中。在這種方式中,每當表被改變時都將自動發生通知,並且應用程式員不可能會忘記發出通知。
NOTIFY以一些重要的方式與 SQL 事務互動。首先,如果一個NOTIFY在一個事務內執行,在事務被提交之前,該通知事件都不會被遞送。這是合適的,因為如果該事務被中止,所有其中的命令都將不會產生效果,包括NOTIFY在內。但如果期望通知事件被立即遞送,那這種行為就會令人不安。其次,如果一個監聽會話收到了一個通知訊號而它正在一個事務中,在該事務完成(提交或者中止)之前,該通知事件將不會被遞送給它串連的用戶端。同樣,原因在於如果一個通知在一個事務內被遞送且該事務後來被中止,我們會希望該通知能以某種方式被撤銷 — 但是伺服器一旦把通知發送給用戶端就無法“收回它”。因此通知事件只能在事務之間遞送。其中的要點是把NOTIFY用作即時訊號的應用應該讓它們事務儘可能短小。
如果在同一事務中使用相同的承載字串多次向同一通道名稱發送訊號,則只向接聽程式傳遞通知事件的一個執行個體。另一方面,帶有不同載荷字串的通知將總是作為不同的通知被遞送。類似地,來自不同事務的通知將不會被摺疊成一個通知。除了丟棄後來產生的週期性通知執行個體之外,NOTIFY保證來自同一個事務的通知按照它們被發送的順序被遞送。還可以保證的是,來自不同事務的訊息會按照其事務被提交的順序遞送。
一個執行NOTIFY的用戶端自己也同時在監聽同一個通知頻道是很常見的事。在這種情況下,和所有其他監聽會話一樣,它會取回一個通知事件。根據應用的邏輯,這可能導致無用的工作,例如從自己剛剛寫入的一個表中讀出相同的更新。可以通過關注發出通知的伺服器處理序 PID(在通知事件訊息中提供)與自己的會話 PID(可以從libpq得到)是否相同來避免這種額外的工作。當兩者相同時,該通知事件就是當前會話自己發出的,所以可以忽略。
文法
NOTIFY channel [ , payload ]參數
channel要對其發訊號的通知頻道的名稱(任意標識符)。payload要通過通知進行溝通的“載荷”字串。這必須是一個簡單的字串。在預設配置下,該字串不能超過 8000 位元組(如果需要發送位元據或者更多資訊,最好是把它放在一個資料庫表中並且發送該記錄的鍵)。
說明
有一個隊列保持著已經發送但是還沒有被所有監聽會話處理的通知。如果該隊列被佔滿,調用NOTIFY的事務將在提交時失敗。該隊列非常大(標準安裝中是 8GB)並且應該足以應付幾乎每一種用例。不過,如果一個會話執行了NOTIFY並且接著長時間進入一個事務,不會發生清理操作。一旦該隊列使用過半,你將在記錄檔中看到警告,它指出哪個會話阻止了清理。在這種情況中,應該確保這個會話結束它的當前事務,這樣清理才能夠進行下去。
函數pg_notification_queue_usage返回隊列中當前被待處理通知所佔據的比例。
一個已經執行了NOTIFY的事務不能為兩階段交易認可做準備。
pg_notify
要發送一個通知,你也能使用函數pg_notify``(``text``, ``text``)。該函數採用頻道名稱作為第一個參數,而載荷則作為第二個參數。如果你需要使用非常量的頻道名稱和載荷,這個函數比NOTIFY命令更容易使用。
樣本
從psql配置和執行一個監聽/通知序列:
LISTEN virtual;
NOTIFY virtual;
Asynchronous notification "virtual" received from server process with PID 8448.
NOTIFY virtual, 'This is the payload';
Asynchronous notification "virtual" with payload "This is the payload" received from server process with PID 8448.
LISTEN foo;
SELECT pg_notify('fo' || 'o', 'pay' || 'load');
Asynchronous notification "foo" with payload "payload" received from server process with PID 14728.