Транзакции не работают нормально в хранимой процедуре PostgreSQL 11 - PullRequest
0 голосов
/ 27 марта 2019

Версия Postgres:
PostgreSQL 11.0 для x86_64-pc-linux-gnu,
, скомпилированная gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-9), 64-разрядная

У меня есть эта хранимая процедура, как показано ниже.Это просто тест.В этой процедуре у меня есть 2 транзакции:

  • Первая должна завершиться нормально (т. Е. Я написал код, чтобы он не сталкивался с какими-либо ошибками, и поэтому он достигнет COMMIT заявление).

  • Предполагается, что вторая транзакция завершится неудачей, поскольку я намеренно ввел в нее ошибку (либо через этот cast там, либо через INSERT, который вызывает нарушение PK).

Кроме того, yb.print_now - это простая функция, которая просто регистрирует (вставляет) сообщения в другую таблицу.

Когда я запускаю эту хранимую процедуру, я ожидаю, что обновления и регистрация сообщений, выполненных первой транзакцией, сохранятся в базе данных, даже несмотря на то, что вторая транзакция завершилась неудачно.

Но этого не происходит, кажется, что обе транзакции откатываются.

  1. Почему это?Я делаю что-то неправильно?

И еще 2 вопроса, которые очень важны для меня.:

Когда происходит ошибка (скажем, как в строке, помеченной ***) и когда управление достигает / переходит к блоку EXCEPTION, у меня возникает ощущение, что транзакция, в которой я находился, уже откатывается, прежде чем я дажедобраться до блока EXCEPTION.Поэтому в блоке исключений я не могу сделать ROLLBACK или COMMIT или что-либо, связанное с транзакцией.Это чувство правильно?

Скажите, что я хочу зафиксировать все, что сделано, несмотря на ошибку, есть ли способ, которым я могу это сделать?
Это именно то, что я хочу здесь.Ошибка - это ошибка ... Хорошо, но я хочу, чтобы все, что произошло до того, как я получил ошибку, было зафиксировано.

Как мне это сделать в Postgres 11?

    CREATE OR REPLACE PROCEDURE yb.test123()
     LANGUAGE plpgsql
    AS $procedure$ 

    DECLARE
        var_cnt int;
        c int;
    BEGIN

        START TRANSACTION; --- 1 ---

        raise notice '001.';

        PERFORM yb.print_now('===> 0010.');

        var_cnt = 0;

        update yb.mbb
        set the_price = the_price + 1   
        where 
        the_id = 23164;

        raise notice '002.';
        PERFORM yb.print_now('===> 0020.');

        raise notice '003.';
        PERFORM yb.print_now('===> 0030.');

        update yb.mbb
        set the_price = the_price + 1 
        where 
        the_id = 23164;

        COMMIT; --- 1 ---

        START TRANSACTION; --- 2 --- 

        c = cast('###a1e3Z' as int);  --- *** --- 

        raise notice '004.';
        PERFORM yb.print_now('===> 0040.');

        update yb.mbb
        set the_price = the_price + 1 
        where 
        the_id = 23164;

        -- insert into yb.mbb(the_id)
        -- values (23164); -- this will throw duplicate PK error

        raise notice '005.';
        PERFORM yb.print_now('===> 0050.');

        COMMIT; --- 2 ---



    EXCEPTION
        WHEN OTHERS THEN

        raise notice 'We are in the exception block now.';
        -- ROLLBACK;
        -- COMMIT;

        RETURN;

    END

    $procedure$;

1 Ответ

1 голос
/ 27 марта 2019

Ошибка происходит в самом начале вашей процедуры, в утверждении

START TRANSACTION;

Как документация гласит:

Новая транзакция запускается автоматически после завершения транзакции с использованием этих команд, поэтому отдельной команды START TRANSACTION не существует.

Это должно ответить на ваш первый вопрос.

Что касается второго, когда вы находитесь в ветви исключений, вы фактически откатили субтранзакцию, которая началась с BEGIN, который принадлежит предложению EXCEPTION (или после последнего COMMIT). Вы все еще в транзакции, поэтому вы можете выдать COMMIT и ROLLBACK.

К вашему третьему вопросу: нет, нет способа зафиксировать все до последнего исключения & rdquo ;. Это можно сделать, только обернув каждый оператор в блок BEGIN ... EXCEPTION ... END, но это серьезно ухудшит вашу производительность (не считая код нечитабельным).

Используйте BEGIN ... EXCEPTION ... END блоков разумно, когда вы ожидаете, что оператор может потерпеть неудачу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...