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 возвращает долю очереди, которая в настоящее время занята ожидающими уведомлениями. Дополнительную информацию см. в разделе Расширенные функции SQL.

Транзакция, которая выполнила 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