Postgresql 在事务完成后执行触发器
在PostgreSQL中,延迟触发器是在事务完成之前(之内)执行还是在事务完成之后执行 报告说: 可延期的Postgresql 在事务完成后执行触发器,postgresql,triggers,transactions,notifications,deferred-execution,Postgresql,Triggers,Transactions,Notifications,Deferred Execution,在PostgreSQL中,延迟触发器是在事务完成之前(之内)执行还是在事务完成之后执行 报告说: 可延期的 不可延期 这控制是否可以延迟约束。约束 不可延期的,将在每次 指挥部。可以推迟检查可推迟的约束 直到事务结束(使用命令) 它没有指定它是否仍在事务内部或外部。我的个人经验表明,它在交易中,我需要它在交易之外 延迟(或初始延迟)触发器是否在事务内部执行?如果是,我如何才能将其执行推迟到交易完成时 为了给你一个提示,我正在使用pg_notify和RabbitMQ()发送消息。我在外部应用程序中
不可延期
这控制是否可以延迟约束。约束
不可延期的,将在每次
指挥部。可以推迟检查可推迟的约束
直到事务结束(使用命令)
它没有指定它是否仍在事务内部或外部。我的个人经验表明,它在交易中,我需要它在交易之外
延迟
(或初始延迟
)触发器是否在事务内部执行?如果是,我如何才能将其执行推迟到交易完成时
为了给你一个提示,我正在使用pg_notify
和RabbitMQ()发送消息。我在外部应用程序中处理此类消息。现在我有一个触发器,它通过在消息中包含记录的id来通知外部应用程序新插入的记录。但以一种不确定的方式,有时,当我试图通过手头的id选择一条记录时,该记录无法找到。这是因为事务尚未完成,并且记录没有实际添加到表中。如果我只能在交易完成后推迟触发器的执行,那么一切都会解决
为了得到更好的答案,让我更接近真实世界来解释情况。实际情况比我之前解释的要复杂一些。如果有人感兴趣的话。由于我不想深入探讨的原因,我必须从另一个数据库发送通知,因此通知实际上是这样发送的:
PERFORM * FROM dblink('hq','SELECT pg_notify(''' || channel || ''', ''' || payload || ''')');
我确信这会使整个情况更加复杂。触发器(包括各种延迟触发器)在事务内部触发
但这并不是问题所在,因为通知是在事务之间传递的
NOTIFY
以一些重要的方式与SQL事务交互。
首先,如果在事务内部执行通知
,则通知
只有在事务完成后才会传递事件
坚信的这是适当的,因为如果事务中止,
其中的所有命令都无效,包括NOTIFY
。但是
如果期望通知事件发生,则可能会令人不安
立即交货。其次,如果听力会话收到
通知信号在事务中时,通知
事件将不会传递到其连接的客户端,直到
事务已完成(提交或中止)。再说一次
理由是,如果通知是在
如果事务后来被中止,则希望通知
以某种方式被撤消-但服务器无法“收回”通知
一旦发送到客户端因此通知事件仅限于
在交易之间交付。结果是
使用NOTIFY
进行实时信令的应用程序应尽量保持
他们的交易很短
我的
只是SQLNOTIFY
命令的一个方便的包装函数
如果在收到通知后找不到某些行,则一定有其他原因!去找吧。可能的候选人:
- 并发事务干扰
- 触发器做的事情比你想象的要多或不同
- 各种各样的编程错误
dblink
至于你以后的补充:
PERFORM * FROM dblink('hq','SELECT pg_notify(''' || channel || ''', ''' || payload || ''')');
。。。应使用重写,以简化并确保语法安全:
PRERFORM dblink('hq', format('NOTIFY %I, %L', channel, payload));
dblink在这里是一个游戏规则改变者,因为它在另一个数据库中打开一个单独的事务。这有时用于伪造自主交易
dblink()
等待远程命令完成。因此,远程事务很可能首先提交:
函数返回查询生成的行
如果您可以从同一事务发送通知,那么这将是一个干净的解决方案
dblink的变通方法
如果必须从其他事务发送通知,则有一种解决方法:
dblink\u send\u query
发送一个异步执行的查询,即不立即等待结果
如果在事务结束之前执行此操作,本地事务将提前3秒()开始提交。选择适当的秒数
这种方法存在固有的不确定性,因为如果出现任何错误,您都不会收到错误消息。对于安全的解决方案,您需要不同的设计。但是,在成功发送命令后,仍然失败的可能性非常小。错过成功通知的几率似乎要高得多,但这已经内置到您当前的解决方案中
安全替代方案
一种更安全的替代方法是写入队列表并轮询它,如中所述。此相关答案演示了如何安全地进行投票:
DO -- or plpgsql function
$$
BEGIN
-- do stuff
PERFORM dblink_connect ('hq', 'your_connstr_or_foreign_server_here');
PERFORM dblink_send_query('con1', format('SELECT pg_sleep(3); NOTIFY %I, %L ', 'Channel', 'payload'));
PERFORM dblink_disconnect('con1');
END
$$;