【问题标题】:Queries and triggers execution order inside transaction查询并触发事务内的执行顺序
【发布时间】:2015-03-10 10:27:42
【问题描述】:

如果在事务内部调用了触发器,是否保证所有触发器(非约束/非延迟触发器)将在事务中的下一个查询开始之前完成。 例如我有下表:

Table a
id    name    is_updated
1     alice   False
2     alice   False
3     Alice   False

在此表上定义的触发器之前的行级别,如果名称字段已更新,则将 is_updated 设置为 True。

我执行以下交易:

BEGIN;
UPDATE table_a SET name = 'Alice' WHERE name = 'alice';
UPDATE table_a SET is_updated = False WHERE is_updated = True;
COMMIT;

是否会在所有触发器完成之前启动第二个 UPDATE 语句?或者触发器在调用触发器的语句内部运行?

UPD1

Postgresql 版本是 9.3。 这里是触发器和相关函数来源:

CREATE TRIGGER a_name_update_trigger
BEFORE UPDATE OF name
FOR EACH ROW
EXECUTE PROCEDURE on_a_name_update();

CREATE OR REPLACE FUNCTION on_a_name_update()
RETURNS TRIGGER AS $$
    BEGIN
        NEW.is_updated = True;
        RETURN NEW;
    END;
$$ LANGUAGE plpgsql;

【问题讨论】:

  • 能否请您显示您的触发器定义和您的 postgresql 版本?
  • @Houari,我已经更新了我的问题

标签: postgresql triggers sqltransaction


【解决方案1】:

没有错,除了我认为触发器的定义应该是这样的:

CREATE OR REPLACE FUNCTION on_a_name_update()
RETURNS TRIGGER AS $$
BEGIN
  NEW.is_updated = true;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER a_name_update_trigger
BEFORE update of name ON table_a 
FOR EACH ROW
EXECUTE PROCEDURE on_a_name_update();

SQLFiddle

所以,通过执行您的查询:

BEGIN;
UPDATE table_a SET name = 'Alice' WHERE name = 'alice';
UPDATE table_a SET is_updated = False WHERE is_updated = True;
COMMIT;

最终更新如期而至:

id    name    is_updated
1    "Alice"    False
2    "Alice"    False
3    "Alice"    False

换句话说,第二次更新是在触发器被触发后执行的(如果列名被更新)

【讨论】:

  • 虽然有可能在触发器结束之前运行第二次 UPDATE 吗?我在文档中找不到它。
  • 不,您不能这样做,因为所有触发器都在同一个事务中执行。我认为如果你解释你真正想做的事情,也许还有另一种方法可以实现它。
  • 我想了解触发器和其他语句是如何在事务内部运行的,因此不会发生意外行为。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-05
  • 2010-09-10
  • 1970-01-01
相关资源
最近更新 更多