【问题标题】:Transaction results in syntax error事务导致语法错误
【发布时间】:2015-02-17 03:20:24
【问题描述】:

这个函数在没有事务块的情况下创建正常。如下所示,我收到以下错误...

错误:输入第 27 行末尾的语法错误:$$ ^ ********** 错误 ********** 错误:输入结束时的语法错误

如果我取出 'COMMIT' 和相应的 'BEGIN' 则运行正常。

这是为什么?

CREATE OR REPLACE FUNCTION ContentDelete (
    creatorUserId BIGINT,
    toDeleteContentId BIGINT)

    RETURNS VOID

    AS $$
    BEGIN
        BEGIN
            IF (SELECT EXISTS(SELECT
                        *
                    FROM
                        tbl_content
                    WHERE
                        ContentId = toDeleteContentId
                        AND
                        UserId = creatorUserId
                    LIMIT 1) AS "exists")

            THEN
                DELETE FROM tbl_content WHERE ParentContentId = toDeleteContentId;
                DELETE FROM tbl_content WHERE ContentId = toDeleteContentId;
            END IF;
        COMMIT;

    END
 $$
 LANGUAGE plpgsql;

【问题讨论】:

  • 您不能在 Postgres 的函数中使用 commit(或 rollback)。函数的调用者需要这样做。

标签: postgresql plpgsql


【解决方案1】:

PostgreSQL 中的函数到处都在事务下运行。它可以是隐式事务(由 Postgres 启动)或显式事务(由用户启动)。而且你不能提交或回滚这个事务,因为它是在函数之外启动的。

如果你的函数没有引发异常,那么结果将被提交(如果其他人没有引发异常)。如果您要强制回滚 - 引发异常。唯一的一种解决方案是回滚外部事务。你的函数可以在 PostgreSQL 中大大减少(虽然你的逻辑看起来很乱):

CREATE OR REPLACE FUNCTION ContentDelete (creatorUserId BIGINT,
                                          toDeleteContentId BIGINT)
RETURNS VOID AS $$
BEGIN
  DELETE FROM tbl_content
     WHERE ContentId = toDeleteContentId
       AND UserId = creatorUserId;
  IF FOUND THEN
    DELETE FROM tbl_content WHERE ParentContentId = toDeleteContentId;
  END IF;
  RETURN;
END;
$$ LANGUAGE plpgsql;

【讨论】:

  • 有趣,尽管您的代码会导致引用完整性异常。
  • 我不知道上下文(完整架构),所以它可能是错误的 - 但通常我们删除内容和后来的父节点。
  • 但是您的代码首先删除了父节点...?您不能在子级之前删除父级,因为子级将引用不存在的行。
猜你喜欢
  • 1970-01-01
  • 2014-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 1970-01-01
相关资源
最近更新 更多