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
.