NOTIFY — сгенерировать событие уведомления
NOTIFYканал[ ,полезная нагрузка]
Команда NOTIFY отправляет событие уведомления вместе
с необязательной «полезная нагрузка» строкой каждому клиентскому приложению, которое
ранее выполнило команду
LISTEN
для указанного имени канала в текущей базе данных.
Уведомления видимы всем пользователям.
канал
NOTIFY предоставляет простой
механизм межпроцессного взаимодействия для группы процессов,
обращающихся к одной и той же базе данных Digital Q.DataBase .
Вместе с уведомлением может быть отправлена строка полезной нагрузки; кроме того, можно реализовать
механизмы более высокого уровня для передачи структурированных данных, используя
таблицы в базе данных для передачи дополнительных данных от отправителя уведомления получателям.
Информация, передаваемая клиенту при событии уведомления, включает в себя имя канала уведомления, PID серверного процесса уведомляющего сеанса PID, а также строку полезной нагрузки (пустую строку, если она не была указана).
Проектировщик базы данных самостоятельно определяет имена каналов, которые будут использоваться в конкретной базе данных, и назначение каждого из них. Как правило, имя канала совпадает с именем какой-либо таблицы в базе данных, а событие уведомления по сути означает: ««Я изменил эту таблицу,
посмотрите на неё, чтобы увидеть изменения»». Однако подобная связь не навязывается
командами NOTIFY и LISTEN commands. Например, проектировщик базы данных может использовать несколько различных имен каналов для сигнализации о различных типах изменений в одной таблице. Кроме того, для разграничения различных случаев может использоваться строка полезной нагрузки.
Когда NOTIFY используется для сигнализации о внесении изменений
в конкретную таблицу, эффективным приемом программирования является размещение
NOTIFY в триггере оператора, срабатывающем при обновлении таблицы.
В этом случае уведомление отправляется автоматически при изменении таблицы,
и разработчик приложения не сможет случайно забыть об этом.
NOTIFY взаимодействует с транзакциями SQL несколькими важными способами. Во-первых, если NOTIFY выполняется внутри транзакции, события уведомления не доставляются до тех пор, пока транзакция не будет зафиксирована. Это обосновано, поскольку в случае отката транзакции все команды внутри неё не имеют эффекта, включая NOTIFY. Однако это может вызвать затруднения, если ожидается немедленная доставка событий уведомления. Во-вторых, если сессия прослушивания получает сигнал уведомления во время выполнения транзакции, событие уведомления не будет доставлено подключенному клиенту до завершения транзакции (фиксации или отмены). Логика здесь та же: если бы уведомление было доставлено внутри транзакции, которая позже была отменена, возникла бы необходимость как-то отозвать это уведомление — но сервер не может «отозвать» уведомление после того, как оно уже отправлено клиенту.
Поэтому события уведомления доставляются только между транзакциями. Следствием этого является то,
что приложения, использующие NOTIFY для передачи сигналов в реальном времени
должны стараться делать свои транзакции короткими.
Если одно и то же имя канала получает сигнал несколько раз с идентичными строками полезной нагрузки в рамках одной и той же транзакции, слушателям доставляется только один экземпляр события уведомления. С другой стороны, уведомления с различными строками полезной нагрузки всегда будут доставляться как отдельные уведомления. Аналогичным образом уведомления из разных транзакций никогда не объединяются в одно. За исключением отбрасывания последующих экземпляров дублирующихся уведомлений,
NOTIFY гарантирует, что уведомления из одной и той же транзакции доставляются в том порядке, в котором они были отправлены. Также гарантируется, что сообщения из разных транзакций доставляются в том порядке, в котором транзакции были зафиксированы.
Обычно клиент, выполняющий NOTIFY
сам прослушивает тот же канал уведомлений. В этом случае он получит событие уведомления так же, как и все остальные прослушивающие сеансы. В зависимости от логики приложения это может привести к выполнению избыточной работы, например к чтению таблицы базы данных для поиска тех же обновлений, которые были только что записаны текущим сеансом. Избежать такой лишней работы можно, проверив, совпадает ли серверный процесс уведомляющего сеанса PID (передаваемый в сообщении о событии уведомления) с серверным процессом текущего сеанса
PID (доступно из libpq). Если они совпадают, событие уведомления является следствием собственных действий и может быть проигнорировано.
каналИмя канала уведомлений (любой идентификатор).
полезная нагрузкаСтрока «полезная нагрузка» , передаваемая вместе с уведомлением. Она должна быть указана в виде простого строкового литерала. В конфигурации по умолчанию ее размер не должен превышать 8000 байт. (Если необходимо передать двоичные данные или большие объемы информации, рекомендуется поместить их в таблицу базы данных и отправить ключ соответствующей записи.)
Существует очередь для хранения уведомлений, которые были отправлены, но ещё не обработаны всеми прослушивающими сеансами. Если эта очередь переполнится,
транзакции, вызывающие NOTIFY завершатся ошибкой при фиксации.
Очередь довольно велика (8 ГБ в стандартной установке), и её объёма должно быть
достаточно практически для любого сценария использования. Однако очистка не может быть выполнена, если сеанс выполняет LISTEN и затем остаётся в состоянии транзакции в течение очень долгого времени. Как только очередь заполнится наполовину, в файле журнала появятся
предупреждения, указывающие на сеанс, препятствующий
очистке. В этом случае необходимо убедиться, что данный сеанс завершает свою текущую транзакцию, чтобы очистка могла быть продолжена.
Функция pg_notification_queue_usage возвращает долю очереди, занятую в настоящее время ожидающими уведомлениями. См. Раздел 2.6.27 для получения дополнительной информации.
Транзакция, в которой была выполнена команда NOTIFY не может быть подготовлена для двухфазной фиксации.
Для отправки уведомления можно также использовать функцию
. Функция принимает имя канала в качестве первого аргумента и полезную нагрузку в качестве второго. Использовать эту функцию гораздо проще,
чем pg_notify(текст,
текст)NOTIFY команду, если необходимо работать с переменными именами каналов и значениями полезной нагрузки.
Настройка и выполнение последовательности LISTEN/NOTIFY в psql:
LISTEN virtual;
NOTIFY virtual;
Асинхронное уведомление "virtual" получено от серверного процесса с PID 8448.
NOTIFY virtual, 'This is the payload';
Асинхронное уведомление "virtual" с полезной нагрузкой "This is the payload" получено от серверного процесса с PID 8448.
LISTEN foo;
SELECT pg_notify('fo' || 'o', 'pay' || 'load');
Асинхронное уведомление "foo" с полезной нагрузкой "payload" получено от серверного процесса с PID 14728.
В стандарте SQL отсутствует NOTIFY соответствующий оператор.