NOTIFY
Генерирует уведомление.
Синтаксис
NOTIFY <channel> [ , <payload> ]
Описание
Команда NOTIFY отправляет уведомление вместе с необязательной строкой payload каждому клиентскому приложению, которое ранее выполнило в текущей базе данных команду LISTEN <channel> с указанным именем канала. Уведомления видны всем пользователям.
NOTIFY предоставляет простой механизм межпроцессного взаимодействия для набора процессов, обращающихся к одной и той же базе данных Greengage. Вместе с уведомлением может быть отправлена строка сообщения payload, а механизмы более высокого уровня обмена структурированными данными могут быть созданы с использованием таблиц базы данных для передачи дополнительных данных от уведомителя к получателям.
Информация, передаваемая клиенту с уведомлением, включает имя канала уведомления, PID серверного процесса сессии, который отправил уведомление, и строку сообщения (будет пустой, если сообщение не указано).
Определить имена каналов, которые будут использоваться в данной базе данных, и их назначения — задача разработчика базы данных. Обычно имя канала совпадает с именем какой-либо таблицы в базе данных, а событие уведомления по сути означает: "Я изменил эту таблицу, посмотрите, что нового". Однако команды NOTIFY и LISTEN не обеспечивают такой связи. Например, разработчик базы данных может использовать несколько разных имен каналов, чтобы сигнализировать о различных типах изменений в одной таблице. Кроме того, строка сообщения может использоваться для выделения различных событий.
При использовании NOTIFY для оповещения об изменениях в конкретной таблице, полезным программным приемом может быть размещение NOTIFY в правиле, которое будет срабатывать при изменениях в таблице. Таким образом, уведомление будет выдаваться автоматически при обновлении таблицы, и разработчик приложения не рискует случайно забыть это сделать.
На работу NOTIFY существенно влияют транзакции SQL. Во-первых, если NOTIFY выполняется внутри транзакции, уведомления не доставляются до тех пор, пока транзакция не будет зафиксирована. Это уместно, поскольку, если транзакция прерывается, все команды внутри нее не оказывают никакого эффекта, включая NOTIFY. Но это может ввести в заблуждение, если ожидается немедленная доставка уведомлений. Во-вторых, если ожидающая сессия получает уведомление внутри транзакции, событие уведомления не будет доставлено подключенному клиенту до тех пор, пока транзакция не будет завершена (либо зафиксирована, либо прервана). Опять же, причина в том, что если уведомление будет доставлено в рамках транзакции, которая затем будет прервана, может возникнуть необходимость отменить уведомление — но сервер не может "забрать назад" уведомление после того, как он отправил его клиенту. Поэтому уведомления доставляются только между транзакциями. Таким образом, в приложениях, использующих NOTIFY для сигнализации в реальном времени, следует минимизировать размер транзакций.
Если в рамках одной транзакции в один канал поступило несколько уведомлений с одинаковым сообщением, сервер базы данных может принять решение о доставке только одного уведомления. С другой стороны, уведомления с различными сообщениями всегда будут доставляться как отдельные уведомления. Аналогично, уведомления от разных транзакций никогда не будут объединены в одно уведомление. За исключением отбрасывания последующих экземпляров дублирующихся уведомлений, NOTIFY гарантирует, что уведомления от одной и той же транзакции доставляются в порядке их отправки. Также гарантируется, что сообщения от разных транзакций доставляются в порядке, в котором были зафиксированы транзакции.
Часто бывает, что клиент, выполняющий NOTIFY, прослушивает тот же канал уведомлений. В этом случае он получит свое же уведомление, как и все остальные прослушивающие сессии. В зависимости от логики приложения, это может привести к бесполезной работе, например, к чтению таблицы базы данных для поиска изменений, которые и были внесены этой же сессией. Избежать такой дополнительной работы можно, проверив, не совпадает ли PID серверного процесса уведомляющей сессии (указанный в сообщении уведомления) с собственным PID сессии (его можно узнать с помощью libpq). Если они совпадают, значит сессия получила уведомление о собственной работе, и его можно игнорировать.
Параметры
| Параметр | Описание |
|---|---|
channel |
Имя канала для передачи уведомления (любой идентификатор) |
payload |
Строка сообщения, которая будет передана вместе с уведомлением. Она должна быть указана в виде простой текстовой константы. В конфигурации по умолчанию она должна быть меньше 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.