2016-02-29 100 views
0

我试图运行PSQL下面的查询 -PSQL“BEGIN TRANSACTION”语句错误

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

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

在您的代码中,根本不需要交易,因为您在ROLLBACK之前只有SELECT数据。这应该工作得很好:

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(这已经非常严格,不锁定整个表格)或咨询锁定(非侵入性更强)。还要注意,插入记录的时候,并不会发生并发冲突,这些记录必须保证是唯一的,比如序列生成的那些记录。

+0

谢谢。这背景是有几十个并行进程同时运行。 'LOCK TABLES'是这个的关键部分,所以每个进程在执行它的INSERT操作时简要地锁定表,这最终防止了双重写入。基于此,我仍然可以插入'LOCK TABLE匹配IN EXCLUSIVE MODE;'?我不认为它默认锁定表 – user2490003