如何在一个事务中禁用PostgreSQL触发器?

27

我需要在一个事务中临时禁用一个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;
3个回答

30

要在 PostgreSQL 会话中暂时禁用所有触发器,请使用以下命令:

SET session_replication_role = replica;

这将仅禁用当前数据库会话的所有触发器。对于批量操作非常有用,但请记住要小心保持数据库一致性。

要重新启用:

SET session_replication_role = DEFAULT;

来源: http://koo.fi/blog/2013/01/08/disable-postgresql-triggers-temporarily/

暂时禁用PostgreSQL触发器


SET session_replication_role = replica; 会锁定表吗? - Daniel L. VanDenBosch
5
回答自己的问题,答案似乎是否定的。 - Daniel L. VanDenBosch

14

你可以禁用这个表中的所有触发器。它应该看起来像这样:

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的更多信息。


7
是的,但我希望它仅在一个SQL事务中被禁用,并且不希望触发器被禁用时阻止表格。禁用触发器:当处于事务中时会锁定表格。 - gori
3
这并没有回答gori的问题。他和我都需要在不锁定表的情况下禁用触发器。假设我的事务需要60秒,如果触发器被禁用,表将被锁定,这在生产环境中是不可接受的。 - Daniel L. VanDenBosch

9

我曾遇到过这个问题,并想出了一个聪明而干净的方法来解决它。

首先,如果正在执行的触发器是导致插入表的触发器,则无法在该触发器内禁用触发器,否则会导致触发器的无限循环 - 这正是我的情况。

我解决问题的方法是将本地参数变量添加到混合中,它本质上充当了全局变量,当已经使用时,它将禁用触发器的进一步调用。

为此,请在触发器函数的开头添加以下代码:

SET LOCAL your.variable_name to 'TRUE';

然后(假设您正在使用pg≥9.6),只需将以下行添加到CREATE TRIGGER 中:

WHEN (current_setting('your.variable_name', 't') <> 'TRUE')

我没有进行任何台式测试,但从之前的经验来看,我希望它非常高效。


2
要禁用触发器链接,您可以查看堆栈深度 - 请查看pg_trigger_depth()函数。 - Amit Goldstein
1
我必须稍微调整一下: when (coalesce(current_setting('pokko.loading'::text, true), 'FALSE') <> 'TRUE'::text) - Brendan
1
截至9.2版本,Amit的说法是正确的,pg_trigger_depth()可能是一种更本地化和适当的解决方案。虽然我没有测试过它,但我相信这也可以很好地工作。 - Alexi Theodore
+1 这是纯粹的天才,也是防止无限循环的一个好方法,如果您正在使用触发器记录表中的更改,然后使用更改日志进行数据库之间的双向同步。对于其他任何尝试此操作的人,请记住变量名必须带点(例如 foo.bar 可以工作,但 foobar 不行,Postgres 将抱怨它不知道配置变量...请参见文档)。 - Eric Mutta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接