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

相關問題