2016-02-29 1 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; 
$$; 

К сожалению, он продолжает erroring с -

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

, и я не могу показаться, выяснить, почему он не любит BEGIN TRANSACTION. Я попытался сыграть с добавлением ; и удалением ключевого слова TRANSACTION.

ответ

1

В анонимном блоке кода 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; 

Обычно вам лучше оставить разрешение параллелизма в СУБД. Использование EXCLUSIVE LOCK в таблице, к которой часто обращаются, замедлит работу всей системы. Если вы используете PG 9.5, посмотрите на INSERT ... ON CONFLICT DO. Во всех версиях вы также можете использовать менее резкие стратегии блокировки, такие как SET TRANSACTION ISOLATION LEVEL SERIALIZABLE (который уже очень строг без блокировки всей таблицы) или консультативные блокировки (гораздо менее инвазивные). Также обратите внимание, что конфликты параллелизма не возникают при вставке записей с ключами, которые гарантированно уникальны, например, генерируемые последовательностью.

+0

Спасибо. Фон для этого заключается в том, что одновременно выполняются десятки параллельных процессов. «LOCK TABLES» является важной частью этого, так что каждый процесс кратковременно блокирует таблицу, пока выполняет ее операции «INSERT», что в конечном итоге предотвращает двойное письмо. Исходя из этого, могу ли я по-прежнему вставлять 'LOCK TABLE спички в EXCLUSIVE MODE,'? Я не думаю, что он блокирует таблицу по умолчанию – user2490003