NOTIFY

NOTIFY — сгенерировать уведомление


Синтаксис

NOTIFY канал [ , полезная_информация ]

Описание

Команда NOTIFY отправляет событие уведомления вместе с необязательной строкой «полезная информация» каждому клиентскому приложению, которое ранее выполнило команду LISTEN канал для указанного имени канала в текущей базе данных. Уведомления видимы для всех пользователей.

NOTIFY предоставляет простой механизм межпроцессной связи для набора процессов, обращающихся к одной и той же базе данных QHB. Строка полезной информации может быть отправлена вместе с уведомлением, а при использовании таблиц в базе данных для передачи дополнительных данных от уведомителя к адресату(ам) можно создать механизмы более высокого уровня для передачи структурированных данных.

Информация, передаваемая клиенту для события уведомления, включает имя канала уведомления, PID серверного процесса сеанса уведомления и строку полезной информации, которая остается пустой, если не была задана.

Выбор подходящих имен каналов и их смысл остаются на усмотрение проектировщика базы данных. Обычно имя канала совпадает с именем некоторой таблицы в базе данных, и событие уведомления, по существу, означает: «я изменил эту таблицу, взгляните на нее, чтобы увидеть, что нового». Но командами NOTIFY и LISTEN подобная ассоциация не навязывается. Например, проектировщик базы данных может использовать несколько различных имен каналов для передачи сигналов о различных видах изменений в одной таблице. Кроме того, строка полезной информации может использоваться для дифференциации различных случаев.

Когда NOTIFY используется для сигнализации о появлении изменений в определенной таблице, полезной методикой программирования является помещение NOTIFY в триггер оператора, который запускают изменения в таблице. Таким образом, уведомление происходит автоматически при изменении таблицы, и программист приложения не может случайно забыть это сделать.

NOTIFY взаимодействует с транзакциями SQL несколькими важными способами. Во-первых, если NOTIFY выполняется внутри транзакции, события уведомления не доставляются, пока транзакция не зафиксируется. Это целесообразно, так как при прерывании транзакции действие всех команд внутри нее, включая NOTIFY, аннулируется. Но это может сбить с толку, если пользователь ожидает, что события уведомления будут доставляться немедленно. Во-вторых, если перехватывающий сеанс получает сигнал уведомления, находясь в транзакции, это событие уведомления не будет доставлено его подключенному клиенту сразу после завершения (фиксации или прерывания) транзакции. Опять же, смысл в том, что если уведомление было доставлено в рамках транзакции, которая позже была прервана, кто-нибудь может захотеть как-то отменить его — но сервер не может «отозвать» уведомление, которое уже отправлено клиенту. Поэтому события уведомлений доставляются только между транзакциями. Подводя итог вышесказанному, приложениям, использующим NOTIFY для сигнализации в режиме реального времени, следует по возможности максимально сокращать продолжительность своих транзакций.

Если из одной транзакции несколько раз сигнализируется одно и то же имя канала с одинаковыми строками полезной информации, сервер баз данных может принять решение о доставке только одного уведомления. С другой стороны, уведомления с различными строками полезной информации всегда будут доставляться по отдельности. Аналогично никогда не будут объединяться и уведомления от различных транзакций. За исключением удаления более поздних вхождений повторяющихся уведомлений, NOTIFY гарантирует, что уведомления от одной и той же транзакции будут доставлены в том же порядке, в каком были отправлены. Также гарантируется, что сообщения от различных транзакций доставляются в том же порядке, в котором эти транзакции были зафиксированы.

Часто бывает, что клиент, выполнивший NOTIFY, ожидает уведомления на том же канале. В этом случае он получит свое же событие уведомления, как и любой другой прослушивающий сеанс. В зависимости от логики приложения, это может привести к бесполезной работе, например чтению таблицы базы данных для поиска тех же обновлений, которые только что были записаны в этом сеансе. Подобной лишней работы можно избежать, отследив, не совпадает ли PID серверного процесса уведомляющего сеанса (предоставленный в сообщении о событии уведомления) с собственным PID сеанса (доступным из libpq). Если они одинаковы, значит, это вернувшееся событие уведомления о ваших собственных действиях, и его можно игнорировать.


Параметры

канал

Название оповещаемого канала уведомлений (любой идентификатор).

полезная_информация

Строка «полезной информации», передаваемая вместе с уведомлением. Она должна задаваться простым строковым литералом. В стандартной конфигурации ее длина должна быть меньше 8000 байт. (Если требуется передать двоичные данные или большой объем информации, лучше поместить их в таблицу базы данных и передать ключ этой записи.)


Примечания

Существует очередь, содержащая уведомления, которые были отправлены, но еще не обработаны всеми прослушивающими сеансами. Если эта очередь переполняется, транзакции, вызывающие NOTIFY, не смогут выполнить фиксацию. Очередь довольно большая (8 ГБ в стандартной установке), так что ее должно хватить для почти каждого случая использования. Однако если в сеансе выполняется LISTEN, а затем происходит очень длительная транзакция, очередь не очищается. Как только эта очередь заполняется наполовину, в файл журнала упреждающей записи записываются предупреждения, где указывается, какой сеанс препятствует очистке очереди. В этом случае следует добиться завершения текущей транзакции в указанном сеансе, чтобы очередь была очищена.

Функция 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.

Совместимость

В стандарте SQL нет команды NOTIFY.


См. также

LISTEN, UNLISTEN