NOTIFYコマンドは、現在のデータベース内で事前にその指定チャネル名についてLISTEN channelコマンドを実行したクライアントアプリケーションに省略可能な"ペイロード"を持つ通知イベントを送ります。
NOTIFYは同一のPostgreSQLデータベースにアクセスするプロセスの集合に対する単純なプロセス間通信の仕組みを提供します。 通知の際にペイロード文字列を送信することができます。 また、データベース内のテーブルを使用して通知者から(1つまたは複数の)リスナに追加的なデータを渡すことにより、構造化されたデータを渡す高度な仕組みを構築することができます。
通知イベントとしてクライアントに渡される情報には、通知チャネル名と通知を行うセッションのサーバプロセスのPID、ペイロード文字列(指定されていなければ空文字列)が含まれます。
与えられたデータベースにおいて使用される通知チャネル名とその意味についての定義は、データベース設計者に任されています。 通知チャネル名には、データベース内のテーブル名と同じものを使用するのが一般的です。 通知イベントは基本的に"私はこのテーブルを変更しました。変更された箇所を確認してください"ということを意味するものです。 しかし、NOTIFYコマンドとLISTENコマンドでは、そのような関連付けは強制されていません。 例えば、データベース設計者は、1つのテーブルに対する異なる種類の変更を通知するために、複数の異なる通知チャネル名を使用することができます。 他の方法としてペイロード文字列を使用して各種様々な状況に対応させることもできます。
特定のテーブルが変更されたことを通知するためにNOTIFYを使用する場合、NOTIFYをテーブル更新時に発行されるルール内に配置すると便利です。 この場合、通知はテーブルが変更された時に自動的に行われるので、アプリケーションプログラマが通知の実行を忘れるといった事故を防ぐことができます。
NOTIFYとSQLトランザクションの間には、いくつかの重要な相互作用があります。 まず、NOTIFYがトランザクション内部で実行された場合、通知イベントはトランザクションがコミットされない限り配送されません。 トランザクションがアボートされた場合、NOTIFYだけでなく、そのトランザクション内で行われたコマンドが全て無効化されるので、これは妥当といえます。 しかし、通知イベントが即座に配送されることを期待していた場合、当惑するかもしれません。 次に、監視中のセッションがトランザクション処理中に通知信号を受け取った場合、そのトランザクションが(コミットもしくはアボートされて)完了するまで、通知イベントは接続しているクライアントに配送されません。 この理由も同じです。トランザクションに通知が配送された後にそのトランザクションがアボートされた場合、何とかして通知を取り消したくなりますが、サーバはいったんクライアントに送信した通知を"取り戻す"ことはできません。 したがって、通知イベントはトランザクションとトランザクションの合間にのみ配送されます。 この結果、実時間レベルでシグナルを処理するため、NOTIFYを使用するアプリケーションではトランザクション処理を短くしておかなければなりません。
同じペイロード文字列を持つ同じチャネル名が同一トランザクション内から複数回通知される場合、 データベースサーバは1つの通知のみを伝えるように決定します。 一方個別のペイロード文字列を持つ通知は常に個別の通知として伝えられます。 同様に別のトランザクションからの通知が1つの通知にまとめられることは決してありません。 重複する通知インスタンスを後で削除する場合は例外ですが、NOTIFYは同一トランザクションからの通知は送信された順番に配送されることを保証します。 また異なるトランザクションからのメッセージがトランザクションのコミット順で配送されることも保証します。
NOTIFYを実行するクライアント自身が、その通知の通知チャネルを監視していることはよくあります。 この場合、同じ通知名を監視する他のセッションに対するのと同じように通知イベントが戻ってきます。 アプリケーションのロジックにもよりますが、これは無駄な作業になることがあります。 例えば、そのセッションが書き出したばかりのデータベースに対する更新を調べるためにテーブルの再読み込みを行う場合などが考えられます。 通知イベントメッセージ内にある通知元セッションのサーバプロセスのPIDと、libpqで得られる自分自身のPIDが同じかどうかに注意することで、こういった余計な作業を回避できます。 PIDが同じであれば、その通知イベントは自分自身から跳ね返ってきたものであり、無視することができます。
シグナルとして送られる通知チャネル名です(任意の識別子)。
通知と一緒に通信される"ペイロード"文字列です。 これは単一の文字列リテラルとして指定されなければなりません。 デフォルトの設定では、8000バイト未満でなければなりません。 (バイナリデータまたは大規模な情報を渡さなければならないのであれば、データベーステーブル内に格納しレコードのキーを送信することが最善です。)
送信済みだがすべての監視セッションで処理されていない通知を保持するためのキューが存在します。 このキューがいっぱいになると、NOTIFYを呼び出すトランザクションのコミットに失敗します。 キューはかなり大きなもの(標準のインストレーションで8ギガバイト)であり、ほとんどすべての環境で十分な大きさであるはずです。 しかしセッションがNOTIFYを実行した後に長期間のトランザクションに入った場合、キューから吐き出すところがなくなります。 キューの半分までたまると、ログファイル内に吐き出しを妨げるセッションを指し示す警告が現れるようになります。 この場合、吐き出し処理が進むように、確実にそのセッションでその現在のトランザクションを完了させるようにしなければなりません
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.