Postgresql 中文操作指南
Description
NOTIFY 命令会将一条通知事件和一个可选的“有效负载”字符串发送到已在当前数据库中对指定的通道名称执行过 LISTEN _channel_ 的每个客户端应用程序。所有人都可以看到通知。
The NOTIFY command sends a notification event together with an optional “payload” string to each client application that has previously executed LISTEN _channel_ for the specified channel name in the current database. Notifications are visible to all users.
NOTIFY 为访问同一 PostgreSQL 数据库的进程集合提供了一种简单的进程间通信机制。可以 همراه با通知发送一个有效负载字符串,并且可以通过使用数据库中的表来从通知者传递给监听者(们)其他数据,以此构建传递结构化数据的更高级机制。
NOTIFY provides a simple interprocess communication mechanism for a collection of processes accessing the same PostgreSQL database. A payload string can be sent along with the notification, and higher-level mechanisms for passing structured data can be built by using tables in the database to pass additional data from notifier to listener(s).
向客户端传递的通知事件信息包括通知通道名称、发送通知的会话服务器进程 PID 和有效负载字符串,如果未指定有效负载字符串,则为空字符串。
The information passed to the client for a notification event includes the notification channel name, the notifying session’s server process PID, and the payload string, which is an empty string if it has not been specified.
数据库设计人员负责定义在给定数据库中将使用的通道名称及其各自的含义。通常来说,通道名称与数据库中某个表的名称相同,而通知事件本质上表示“我更改了此表,查看一下以了解有什么新变化”。但 NOTIFY 和 LISTEN 命令并不会强制执行此类关联。例如,数据库设计人员可以用几个不同的通道名称来表示对同一张表所做的不同类型的更改。此外,也可以使用有效负载字符串来区分各种情况。
It is up to the database designer to define the channel names that will be used in a given database and what each one means. Commonly, the channel name is the same as the name of some table in the database, and the notify event essentially means, “I changed this table, take a look at it to see what’s new”. But no such association is enforced by the NOTIFY and LISTEN commands. For example, a database designer could use several different channel names to signal different sorts of changes to a single table. Alternatively, the payload string could be used to differentiate various cases.
当 NOTIFY 用于表示对特定表所做更改的发生时,一种有用的编程技术是在由表更新触发的语句触发器中放置 NOTIFY 。通过这种方式,当表发生更改时可以自动发出通知,并且应用程序程序员不会忘记意外地执行此操作。
When NOTIFY is used to signal the occurrence of changes to a particular table, a useful programming technique is to put the NOTIFY in a statement trigger that is triggered by table updates. In this way, notification happens automatically when the table is changed, and the application programmer cannot accidentally forget to do it.
NOTIFY 以一些重要方式与 SQL 事务交互。首先,如果 NOTIFY 在事务中执行,则不会在提交事务之前传递通知事件。这是合适的,因为如果事务中止,则事务中的所有命令均已失效,包括 NOTIFY 。但如果原本期望立即传递通知事件,可能会令人不安。其次,如果在某个事务中接收到一条通知信号,则在完成事务(已提交或中止)之后,才会将通知事件传递到它所连接的客户端。同样,理由是如果在某个稍后被中止的事务中传递了通知,则会希望以某种方式撤销该通知 — 但服务器一旦向客户端发送通知,就无法“收回”。因此,只能在事务之间传递通知事件。这样做的结果是, NOTIFY 应用程序用于实时信令时,应该尝试保持事务的精简。
NOTIFY interacts with SQL transactions in some important ways. Firstly, if a NOTIFY is executed inside a transaction, the notify events are not delivered until and unless the transaction is committed. This is appropriate, since if the transaction is aborted, all the commands within it have had no effect, including NOTIFY. But it can be disconcerting if one is expecting the notification events to be delivered immediately. Secondly, if a listening session receives a notification signal while it is within a transaction, the notification event will not be delivered to its connected client until just after the transaction is completed (either committed or aborted). Again, the reasoning is that if a notification were delivered within a transaction that was later aborted, one would want the notification to be undone somehow — but the server cannot “take back” a notification once it has sent it to the client. So notification events are only delivered between transactions. The upshot of this is that applications using NOTIFY for real-time signaling should try to keep their transactions short.
如果在同一事务中多次使用相同有效负载字符串发出同一个通道名称信号,则只会在监听器之间传递一个通知事件实例。另一方面,具有不同有效负载字符串的通知将始终作为不同的通知进行传递。同样,来自不同事务的通知将永远不会折叠到一个通知中。除了删除重复通知的后面实例外, NOTIFY 还保证以发送的顺序传递来自同一事务的通知。同样保证的是,按照提交事务的顺序传递来自不同事务的消息。
If the same channel name is signaled multiple times with identical payload strings within the same transaction, only one instance of the notification event is delivered to listeners. On the other hand, notifications with distinct payload strings will always be delivered as distinct notifications. Similarly, notifications from different transactions will never get folded into one notification. Except for dropping later instances of duplicate notifications, NOTIFY guarantees that notifications from the same transaction get delivered in the order they were sent. It is also guaranteed that messages from different transactions are delivered in the order in which the transactions committed.
执行 NOTIFY 的客户端经常会监听它本身的同一个通知通道。在这种情况下,它将获得一条通知事件,就像所有其他监听会话一样。根据应用程序逻辑,这可能会导致无用的工作,例如读取数据库表以查找该会话刚刚写入的相同更新。如果发现发送通知的会话的服务器进程 PID(在通知事件消息中提供)与自己的会话 PID(libpq 提供)相同时,可以避免这些额外工作。当它们相同的时候,通知事件是自己工作的反弹,可以忽略。
It is common for a client that executes NOTIFY to be listening on the same notification channel itself. In that case it will get back a notification event, just like all the other listening sessions. Depending on the application logic, this could result in useless work, for example, reading a database table to find the same updates that that session just wrote out. It is possible to avoid such extra work by noticing whether the notifying session’s server process PID (supplied in the notification event message) is the same as one’s own session’s PID (available from libpq). When they are the same, the notification event is one’s own work bouncing back, and can be ignored.
Parameters
-
channel
-
Name of the notification channel to be signaled (any identifier).
-
-
payload
-
The “payload” string to be communicated along with the notification. This must be specified as a simple string literal. In the default configuration it must be shorter than 8000 bytes. (If binary data or large amounts of information need to be communicated, it’s best to put it in a database table and send the key of the record.)
-
Notes
有一个队列保存已发送但尚未由所有监听会话处理的通知。如果此队列已满,则调用 NOTIFY 的事务将在提交时失败。这个队列很大(标准安装中为 8GB),应该足够满足几乎所有用例。但是,如果某个会话执行了 LISTEN ,然后又进入了很长时间的事务,则不会进行任何清理。当队列已满的时候,你将在日志文件中看到警告,指示你查看正在阻止清理的会话。在这种情况下,你应该确保会话结束当前事务,以便清理可以继续。
There is a queue that holds notifications that have been sent but not yet processed by all listening sessions. If this queue becomes full, transactions calling NOTIFY will fail at commit. The queue is quite large (8GB in a standard installation) and should be sufficiently sized for almost every use case. However, no cleanup can take place if a session executes LISTEN and then enters a transaction for a very long time. Once the queue is half full you will see warnings in the log file pointing you to the session that is preventing cleanup. In this case you should make sure that this session ends its current transaction so that cleanup can proceed.
pg_notification_queue_usage 函数返回当前由未决通知占用的队列部分。有关更多信息,请参见 Section 9.26 。
The function pg_notification_queue_usage returns the fraction of the queue that is currently occupied by pending notifications. See Section 9.26 for more information.
已执行 NOTIFY 的事务不能对两阶段提交做好准备。
A transaction that has executed NOTIFY cannot be prepared for two-phase commit.
pg_notify
要发送一条通知,你还可以使用 _pg_notify ( text , text ) . The function takes the channel name as the first argument and the payload as the second. The function is much easier to use than the _NOTIFY 命令(如果你需要处理非常量通道名称和有效负载)。
To send a notification you can also use the function _pg_notify(text, text). The function takes the channel name as the first argument and the payload as the second. The function is much easier to use than the _NOTIFY command if you need to work with non-constant channel names and payloads.
Examples
从 psql 配置并执行一个 listen/notify 序列:
Configure and execute a listen/notify sequence from 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.