NOTIFY命令发送一个通知事件连同一个可选择的"payload" 字符串到每个客户端应用程序,这些应用程序已经预先为当前数据库的指定通道名称执行 LISTEN channel。
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.