如何仅在一个事务中禁用 PostgreSQL 触发器?
Posted
技术标签:
【中文标题】如何仅在一个事务中禁用 PostgreSQL 触发器?【英文标题】:How to disable PostgreSQL triggers in one transaction only? 【发布时间】:2016-10-10 09:30:45 【问题描述】:我需要在事务中临时禁用一个 PostgreSQL 触发器,但没有硬锁定表。有人知道这是否可能吗?
类似这样的事情,没有锁定表和禁用此事务之外的触发器。
BEGIN TRANSACTION;
ALTER TABLE foo DISABLE TRIGGER bar;
-- DO SOME UPDATES ON foo
UPDATE foo set field = 'value' where field = 'test';
ALTER TABLE foo ENABLE TRIGGER bar;
COMMIT;
【问题讨论】:
【参考方案1】:您可以在此表中禁用所有触发器。它应该是这样的:
ALTER TABLE tblname DISABLE TRIGGER USER;
Your SQL;
ALTER TABLE tblname ENABLE TRIGGER USER;
要禁用单个触发器,请使用:
ALTER TABLE tblname DISABLE TRIGGER trigger_name;
Your SQL;
ALTER TABLE tblname ENABLE TRIGGER trigger_name;
您可以在文档中阅读有关 ALTER TABLE 的更多信息。
【讨论】:
是的,但我希望它只在一个 sql 事务中被禁用,并且不想在触发器被禁用时阻止表。 DISABLE TRIGGER : 在事务中硬锁表 这不能回答 gori 的问题。他和我需要在不锁定桌子的情况下禁用触发器。假设我的交易需要 60 秒并且触发器被禁用。桌子将被锁定,这在生产中是不可接受的。【参考方案2】:要暂时禁用 PostgreSQL 会话中的所有触发器,请使用以下命令:
SET session_replication_role = replica;
仅禁用当前数据库会话的所有触发器。对批量操作很有用,但请记住要小心保持数据库的一致性。
重新启用:
SET session_replication_role = DEFAULT;
来源:http://koo.fi/blog/2013/01/08/disable-postgresql-triggers-temporarily/
【讨论】:
SET session_replication_role = replica;
最终会锁定表吗?
回答我自己的问题似乎不是【参考方案3】:
我遇到了同样的问题,并想出了一个聪明而干净的方法来解决它。
首先,如果触发器是您当前正在执行的触发器,则您不能禁用触发器内。那是我的场景——我插入到一个表中是因为插入它——否则会导致触发器的无限循环。
我解决它的方法是在混合中添加一个局部参数变量,该变量基本上充当全局变量,当触发器已经被使用时,它将禁用触发器的进一步调用。
为此,请在触发器函数的最开始添加以下代码:
SET LOCAL your.variable_name to 'TRUE';
然后(假设您使用 pg ≥ 9.6)您只需将以下行添加到您的CREATE TRIGGER
:
WHEN (current_setting('your.variable_name', 't') <> 'TRUE')
我没有做过任何基准测试,但根据我之前的经验,我希望它非常高效。
【讨论】:
要禁用触发器链接,您可以查看堆栈深度 - 查看 pg_trigger_depth() 函数 我不得不稍微调整一下:when (coalesce(current_setting('pokko.loading'::text, true), 'FALSE') <> 'TRUE'::text)
从 9.2 开始,Amit 是正确的,pg_trigger_depth()
可能是更本地和更合适的解决方案。我还没有测试过,但我相信这也能正常工作。以上是关于如何仅在一个事务中禁用 PostgreSQL 触发器?的主要内容,如果未能解决你的问题,请参考以下文章