PSQL" BEGIN TRANSACTION"声明错误

时间:2016-02-29 00:50:47

标签: sql postgresql transactions psql

我试图在PSQL中运行以下查询 -

DO $$
  BEGIN TRANSACTION
  LOCK TABLE tags IN EXCLUSIVE MODE;
  IF (SELECT COUNT(*)
     FROM tags
     WHERE user_id = 1) > 3
  THEN
    INSERT INTO "tags" ("user_id", "friend_id", "status", "explanation", "score", "created_at", "updated_at")
    VALUES (1, 4, 'pending', '', 0.0, '2016-02-29 00:43:58.969313', '2016-02-29 00:43:58.969313')
    RETURNING "id";

    INSERT INTO "tags" ("user_id", "friend_id", "status", "explanation", "score", "created_at", "updated_at")
    VALUES (4, 1, 'pending', '', 0.0, '2016-02-29 00:43:58.969313', '2016-02-29 00:43:58.969313')
    RETURNING "id";
  ELSE
    ROLLBACK;
  END IF;

  COMMIT;
$$;

不幸的是,它不断出错 -

ERROR:  syntax error at or near "TRANSACTION"
LINE 2:   BEGIN TRANSACTION
                ^

我似乎无法弄清楚为什么它不喜欢BEGIN TRANSACTION。我尝试添加;并删除关键字TRANSACTION

1 个答案:

答案 0 :(得分:3)

在匿名代码块中BEGIN表示代码的开头,而不是SQL命令BEGIN。请注意,函数(包括匿名代码块)在其自己的事务中运行,因此您通常不需要显式的附加事务。

在您的代码中,根本不需要事务,因为您SELECT之前只有ROLLBACK数据。这应该可以正常工作:

DO $$
DECLARE
  cnt integer;
BEGIN
  SELECT count(*) INTO cnt
  FROM tags
  WHERE user_id = 1;
  IF cnt > 3 THEN
    INSERT INTO "tags" ("user_id", "friend_id", "status", "explanation", "score", "created_at", "updated_at")
    VALUES (1, 4, 'pending', '', 0.0, '2016-02-29 00:43:58.969313', '2016-02-29 00:43:58.969313');

    INSERT INTO "tags" ("user_id", "friend_id", "status", "explanation", "score", "created_at", "updated_at")
    VALUES (4, 1, 'pending', '', 0.0, '2016-02-29 00:43:58.969313', '2016-02-29 00:43:58.969313');
  END IF;
END;
$$ LANGUAGE plpgsql;

通常最好将并发解决方案留给DBMS。在经常访问的表上使用EXCLUSIVE LOCK会降低整个系统的速度。如果您使用的是PG 9.5,请查看INSERT ... ON CONFLICT DO。在所有版本中,您还可以使用不那么激烈的锁定策略,例如SET TRANSACTION ISOLATION LEVEL SERIALIZABLE(已经非常严格而不锁定整个表)或咨询锁(更少侵入性)。另请注意,插入具有唯一保证唯一的键的记录(例如序列生成的记录)时,不会发生并发冲突。