NOTIFY命令向当前数据库中所有执行过 LISTEN channel, 正在监听特定通道名字的前端应用发送一个通知事件和一个可选的"payload"字符串。 通知对所有用户可见。
NOTIFY为访问同一个PostgreSQL 数据库的一组进程提供了一种简单的进程间通讯机制。负载字符串可以和通知一起发送, 并且传送结构化数据的更高级的机制可以通过使用数据库中的表从通知者传递数据到接收者。
传递给前端的通知事件包括通知通道名、发出通知的后端进程PID 和负载字符串,如果已经指定了字符串则该负载字符串为空。
定义将要用于给定数据库的通道名和每个意味着什么取决于数据库设计者。 通常,通知通道名与数据库里的表的名字相同,通知事件实际上意味着"我修改了此数据库, 请看一眼有什么新东西"。NOTIFY和LISTEN 命令并不强制这种联系。例如,数据库设计者可以使用几个不同的通道名来标志一个表的几种不同改变。 另外,负载字符串可以用来区分各种情况。
当NOTIFY用于通知某一特定表修改的动作的发生, 一个实用的编程技巧是将NOTIFY放在一个由表更新触发的规则里。用这种方法, 通知将在表更新的时候自动触发,而且应用程序员不会碰巧忘记处理它。
NOTIFY和 SQL 事务用某种重要的方法进行交换。首先,如果NOTIFY 在事务内部执行,通知事件直到事务提交才会送出。这么做是有道理的,因为如果事务退出了, 那么在它里面的所有命令都没有效果(包括NOTIFY)。但如果有人希望通知事件立即发送, 这就不太好了。其次,当一个正在监听的会话在一次事务内收到一个通知信号, 直到本次事务完成(提交或退出)之前,该通知事件将不被送到与之相连的客户端。同样, 如果一个通知在事务内部发送出去了,而该事务稍后又退出了,就希望通知可以在某种程度上被撤消, 因为通知一旦发送出去,服务器便不能从客户端"收回"通知,所以通知事件只是在事务之间传递。 这一点就要求使用NOTIFY作为实时信号的应用应该确保他们的事务尽可能短。
如果相同的通道名已经从相同的事务中发出了同样的负载字符串多次, 数据库服务器可以决定只送出一个字符串通知。另一方面,不同负载字符串的通知将总是作为不同通知传送。 相似的,来自不同事件的通知将永远不会被并入一个通知。除了删除稍后复制通知的实例, NOTIFY保证来自相同事务的通知以它们被传送的顺序到达。 也保证来自不同事务的信息以事务提交的顺序到达。
客户端经常会自己发送与正在监听的通知通道一样的NOTIFY。 这时它(客户端)也和其它正在监听的会话一样收到一个通知事件。 这样可能导致一些无用的工作(与应用逻辑有关)。例如, 对客户端刚写过的表又进行一次读操作以发现是否有更新。 可以通过检查服务器进程的PID(在通知事件中提供)是否与自己的会话的PID 一致(从libpq中取得)避免这样的额外工作。当他们一样时, 说明这是其自身回弹的信息,可以忽略。
生成信号(通知)的通知通道(任何标识符)。
"payload"字符串与通知交流。必须指定为简单的字符串文本。缺省配置中必须少于8000字节。 (如果二进制数据或大量的信息需要交流,最好放在数据库表中并发送该记录的键字。)
有一个已经发送的持有通知但目前还未被所有监听会话处理的序列。如果这个序列满了, 会话调用NOTIFY将会在提交时失败。序列是相当大的(标准安装中是8GB) 并且应该足够为几乎每个使用情况大。但是,如果会话执行LISTEN 并且然后进入一个事务很长时间那么将不会有清除发生。一旦序列是半满的, 您将在日志中看到警告指向您的会话阻止清除。在这种情况下,应该确保这个会话结束他的当前事务, 这样清理能够进行。
一个已经执行了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.