Перейти к основному содержимому

Уровень 3.0

Предусловия:

  • Изучена лекция 1 «Свойства транзакций»

Анализ аномалий при различных уровнях изоляции​

  1. Откройте терминал и подключитесь в psql к базе данных postgres c ролью postgres:

    [student@pkles-gt0040523 ~]$ sudo -iu postgres
    -bash-4.4$ psql
    psql (15.5)
    Введите "help", чтобы получить справку.
  2. Проверьте уровень изоляции по умолчанию:

    postgres=# SHOW default_transaction_isolation;
    default_transaction_isolation
    -------------------------------
    read committed
    (1 строка)

    Как и ожидалось, уровень изоляции по умолчанию Read Committed.

    Если уровень изоляции по умолчанию окажется другим, то сбросьте значение параметра default_transaction_isolation:

    postgres=# ALTER SYSTEM RESET default_transaction_isolation;
    ALTER SYSTEM
    postgres=# SELECT pg_reload_conf();
    pg_reload_conf
    ----------------
    t
    (1 строка)
  3. Создайте пользователя student, базу данных службы доставки и подключитесь к ней:

    postgres=# CREATE ROLE student WITH PASSWORD 'student' LOGIN;
    CREATE ROLE
    postgres=# CREATE DATABASE delivery_db OWNER student;
    CREATE DATABASE
    postgres=# \c delivery_db student
    Вы подключены к базе данных "delivery_db" как пользователь "student".
  4. Создайте таблицу hubs, в которой хранится информация о количестве посылок в сортировочных центрах, и наполните ее тестовыми данными:

    delivery_db=> CREATE TABLE hubs(hub_id integer PRIMARY KEY, city text, packages_amount integer);
    CREATE TABLE
    delivery_db=> INSERT INTO hubs VALUES (1, 'Москва', 300), (2, 'Москва', 200), (3, 'Санкт-Петербург', 400);
    INSERT 0 3
  5. Настройте приглашение в psql с указанием номера обслуживающего процесса:

    delivery_db=> \set PROMPT1 '%p%R%x%# '
    80642=> \set PROMPT2 '%p%R%x%# '

    Теперь в приглашении указан pid обслуживающего процесса. Это необходимо для идентификации разных сеансов psql.

  6. Откройте второй терминал и подключитесь в psql к базе данных delivery_db с ролью student:

    [student@pkles-gt0040523 ~]$ psql -d delivery_db
    psql (15.5)
    Введите "help", чтобы получить справку.
  7. Настройте приглашение во втором сеансе psql с указанием номера обслуживающего процесса:

    delivery_db=> \set PROMPT1 '%p%R%x%# '
    80667=> \set PROMPT2 '%p%R%x%# '

Уровень изоляции Read Committed​

Отсутствие грязного чтения​

  1. В первом сеансе psql начните транзакцию с уровнем изоляции Read Committed и проверьте содержимое таблицы hubs:

    80642=> BEGIN;
    BEGIN
    80642=*> SELECT * FROM hubs;
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    1 | Москва | 300
    2 | Москва | 200
    3 | Санкт-Петербург | 400
    (3 строки)

    В данном случае при открытии транзакции явно указывать уровень изоляции не потребовалось, так как уровень Read Committed используется по умолчанию. Обратите внимание, что после открытия транзакции в приглашение psql добавился символ "*".

  2. В первом сеансе отправьте 50 посылок из одного сортировочного центра в другой:

    80642=*> UPDATE hubs SET packages_amount = packages_amount - 50 WHERE hub_id = 1 RETURNING packages_amount AS msc_amount_1;
    msc_amount_1
    --------------
    250
    (1 строка)

    UPDATE 1
    80642=*> UPDATE hubs SET packages_amount = packages_amount + 50 WHERE hub_id = 3 RETURNING packages_amount AS spb_amount_3;
    spb_amount_3
    --------------
    450
    (1 строка)

    UPDATE 1
    80642=*> SELECT * FROM hubs;
    hub_id | city | packages_amount
    -------+-----------------+-----------------
    2 | Москва | 200
    1 | Москва | 250
    3 | Санкт-Петербург | 450
    (3 строки)

    Обратите внимание, что внутри транзакции изменения самой транзакции видны.

  3. Во втором сеансе откройте транзакцию с тем же уровнем изоляции Read Committed и проверьте содержимое таблицы hubs:

    80667=> BEGIN;
    BEGIN
    80667=*> SELECT * FROM hubs;
    hub_id | city | packages_amount
    -------+-----------------+-----------------
    1 | Москва | 300
    2 | Москва | 200
    3 | Санкт-Петербург | 400
    (3 строки)

    Изменения незафиксированной первой транзакции не видны, значит, аномалия грязного чтения не допускается.

  4. В первом сеансе зафиксируйте транзакцию:

    80642=*> COMMIT;
    COMMIT
  5. Во втором сеансе повторите выполнение запроса:

    80667=*> SELECT * FROM hubs;
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    2 | Москва | 200
    1 | Москва | 250
    3 | Санкт-Петербург | 450
    (3 строки)

    Теперь изменения первой транзакции видны.

  6. Во втором сеансе зафиксируйте транзакцию:

    80667=*> COMMIT;
    COMMIT

Неповторяющееся чтение​

  1. В первом сеансе начните транзакцию с уровнем изоляции Read Committed и отправьте 50 посылок из Санкт-Петербурга в Москву с условием того, что московские сортировочные центры не могут хранить более 300 посылок каждый:

    80642=> BEGIN;
    BEGIN
    80642=*> DO $$
    BEGIN
    IF (SELECT packages_amount FROM hubs WHERE hub_id = 1) >= 300-50 THEN
    PERFORM pg_sleep(30);
    UPDATE hubs SET packages_amount = packages_amount + 50 WHERE hub_id = 1;
    UPDATE hubs SET packages_amount = packages_amount - 50 WHERE hub_id = 3;
    END IF;
    END;
    $$;

    Ответ будет выдан по прошествии 30 секунд:

    DO

    Для задания условия предельной емкости сортировочного центра в г. Москва использовался условный оператор в анонимном блоке DO на языке PL/pgSQL. Для создания искусственной задержки между запросом в условии и командами обновления таблиц использовалась команда PERFORM pg_sleep(30);, выполняющая запрос и отбрасывающая результаты его выполнения.

  2. Во время «сна» первой транзакции во втором сеансе отправьте 50 посылок из одного сортировочного центра в Москве в другой с фиксацией транзакции:

    80667=> BEGIN;
    BEGIN
    80667=*> UPDATE hubs SET packages_amount = packages_amount - 50 WHERE hub_id = 2 RETURNING packages_amount AS msc_amount_2;
    msc_amount_2
    --------------
    150
    (1 строка)

    UPDATE 1
    80667=*> UPDATE hubs SET packages_amount = packages_amount + 50 WHERE hub_id = 1 RETURNING packages_amount AS msc_amount_1;
    msc_amount_1
    --------------
    300
    (1 строка)

    UPDATE 1
    80667=*> COMMIT;
    COMMIT
  3. В первом сеансе дождитесь выполнения предыдущего оператора и посмотрите содержимое таблицы hubs:

    80642=*> SELECT * FROM hubs;
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    2 | Москва | 150
    1 | Москва | 350
    3 | Санкт-Петербург | 400
    (3 строки)

    В результате в сортировочном центре с hub_id=1 превышена его емкость (packages_amount=350), то есть нарушено одно из правил согласованности. Это произошло по причине того, что уровень изоляции Read Committed допускает аномалию неповторяющегося чтения. Если бы запрос в условном операторе первой транзакции SELECT packages_amount FROM hubs WHERE hub_id = 1 был бы выполнен повторно после фиксации второй транзакции, он бы выдал другие результаты, и операции обновления в теле условного оператора не были бы выполнены.

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

    Чтобы избежать этого, на уровне изоляции Read Committed рекомендуется использовать атомарные операторы, такие как общие табличные выражения (CTE) или INSERT ... ON CONFLICT .... В данном случае проблему можно было решить путем использования ограничения целостности CHECK, проверяющего предельную емкость сортировочных центров в Москве. В отдельных случаях могут использоваться явные блокировки, например с помощью оператора SELECT FOR UPDATE. Однако это сводит на нет преимущества многоверсионности.

  4. В первом сеансе откатите транзакцию:

    80642=*> ROLLBACK;
    ROLLBACK

Потерянные изменения​

  1. В первом сеансе начните транзакцию с уровнем Read Committed и получите количество посылок в сортировочном центре в г. Санкт-Петербург с сохранением результата в переменную psql:

    80642=> BEGIN;
    BEGIN
    80642=*> SELECT packages_amount AS spb_amount FROM hubs WHERE hub_id = 3 \gset
    80642=*> \echo :spb_amount
    450
  2. То же самое сделайте во втором сеансе:

    80667=> BEGIN;
    BEGIN
    80667=*> SELECT packages_amount AS spb_amount FROM hubs WHERE hub_id = 3 \gset
    80667=*> \echo :spb_amount
    450
  3. В первом сеансе добавьте 50 посылок к сортировочному центру в г. Санкт-Петербург и зафиксируйте изменения:

    80642=*> UPDATE hubs SET packages_amount = :spb_amount + 50 WHERE hub_id = 3 RETURNING packages_amount AS spb_amount_3;
    spb_amount_3
    -----------------
    500
    (1 строка)

    UPDATE 1
    80642=*> COMMIT;
    COMMIT
  4. Во втором сеансе сделайте то же самое:

    80667=*> UPDATE hubs SET packages_amount = :spb_amount + 50 WHERE hub_id = 3 RETURNING packages_amount AS spb_amount_3;
    spb_amount_3
    -----------------
    500
    (1 строка)

    UPDATE 1
    80667=*> COMMIT;
    COMMIT

    В результате 50 посылок в сортировочном центре г. Санкт-Петербург утеряно. Это произошло по причине того, что вторая транзакция не учла изменений, выполненных первой транзакцией (хотя они ей были видны), но полагалась на промежуточные результаты, сохраненные в переменной spb_amount. Это и есть пример аномалии потерянных изменений, которая может возникать таким образом на уровне изоляции Read Committed.

Уровень изоляции Repeatable Read​

Отсутствие неповторяющегося чтения​

  1. В первом сеансе начните транзакцию с уровнем изоляции Read Committed и отправьте из Санкт-Петербурга в Москву 50 посылок:

    80642=> BEGIN;
    BEGIN
    80642=*> UPDATE hubs SET packages_amount = packages_amount - 50 WHERE hub_id = 3 RETURNING packages_amount AS spb_amount_3;
    spb_amount_3
    ------------
    450
    (1 строка)

    UPDATE 1
    80642=*> UPDATE hubs SET packages_amount = packages_amount + 50 WHERE hub_id = 2 RETURNING packages_amount AS msc_amount_2;
    msc_amount_2
    ------------
    200
    (1 строка)

    UPDATE 1
  2. Во втором сеансе начните транзакцию с уровнем изоляции Repeatable Read и посмотрите содержимое таблицы hubs:

    80667=> BEGIN ISOLATION LEVEL REPEATABLE READ;
    BEGIN
    80667=*> SELECT * FROM hubs;
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    1 | Москва | 300
    2 | Москва | 150
    3 | Санкт-Петербург | 500
    (3 строки)

    Как и ожидалось, незафиксированные изменения первой транзакции не видны.

  3. В первом сеансе зафиксируйте транзакцию:

    80642=*> COMMIT;
    COMMIT
  4. Во втором сеансе повторите выполнение запроса:

    80667=*> SELECT * FROM hubs;
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    1 | Москва | 300
    2 | Москва | 150
    3 | Санкт-Петербург | 500
    (3 строки)

    Несмотря на фиксацию первой транзакции, во второй транзакции изменения по-прежнему не видны. Таким образом, на уровне изоляции Repeatable Read не допускается аномалия неповторяющегося чтения. Согласованность не может быть нарушена в результате фиксации других транзакций в промежутке между выполнением операторов.

Отсутствие фантомного чтения​

  1. В первом сеансе начните транзакцию с уровнем изоляции Read Committed и добавьте в Санкт-Петербург новый сортировочный центр с фиксацией транзакции:

    80642=> BEGIN;
    BEGIN
    80642=*> INSERT INTO hubs VALUES(4, 'Санкт-Петербург', 0);
    INSERT 0 1
    80642=*> COMMIT;
    COMMIT
  2. Во втором сеансе транзакции, которая по-прежнему не зафиксирована, посмотрите содержимое таблицы hubs:

    80667=*> SELECT * FROM hubs;
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    1 | Москва | 300
    2 | Москва | 150
    3 | Санкт-Петербург | 500
    (3 строки)

    Добавленная в первой транзакции строка также не видна. Таким образом, на уровне изоляции Repeatable Read также не допускается аномалия фантомного чтения.

  3. Во втором сеансе зафиксируйте транзакцию:

    80667=*> COMMIT;
    COMMIT

Отсутствие потерянных изменений​

  1. В первом сеансе начните транзакцию с уровнем изоляции Repeatable Read и получите количество посылок в сортировочном центре в г. Санкт-Петербург (hub-id = 3) с сохранением результата в переменную psql:
80642=> BEGIN ISOLATION LEVEL REPEATABLE READ;
BEGIN
80642=*> SELECT packages_amount AS spb_amount_3 FROM hubs WHERE hub_id = 3 \gset
80642=*> \echo :spb_amount_3
450
  1. То же самое сделайте во втором сеансе:
80667=> BEGIN ISOLATION LEVEL REPEATABLE READ;
BEGIN
80667=*> SELECT packages_amount AS spb_amount_3 FROM hubs WHERE hub_id = 3 \gset
80667=*> \echo :spb_amount_3
450
  1. В первом сеансе добавьте 50 посылок к сортировочному центру в г. Санкт-Петербург (hub_id = 3) и зафиксируйте изменения:

    80642=*> UPDATE hubs SET packages_amount = :spb_amount_3 + 50 WHERE hub_id = 3 RETURNING packages_amount AS spb_amount_3;
    spb_amount_3
    -----------------
    500
    (1 строка)

    UPDATE 1
    80642=*> COMMIT;
    COMMIT
  2. Во втором сеансе также добавьте 50 посылок к сортировочному центру в г. Санкт-Петербург (hub_id = 3):

    80667=*> UPDATE hubs SET packages_amount = :spb_amount_3 + 50 WHERE hub_id = 3 RETURNING packages_amount AS spb_amount_3;
    ERROR: could not serialize access due to concurrent update

    В результате получена ошибка сериализации, что предотвратило возникновение аномалии потерянных изменений. На уровне изоляции Repeatable Read разработчик должен быть готов к обработке таких ошибок с повторным выполнением транзакций.

  3. Во втором сеансе откатите транзакцию:

    80667=*> ROLLBACK;
    ROLLBACK

Несогласованная запись​

  1. В первом сеансе начните транзакцию с уровнем изоляции Repeatable Read и добавьте 100 посылок в сортировочный центр в г. Санкт-Петербург (hub_id = 4) с условием того, что суммарная емкость сортировочных центров в г. Санкт-Петербург составляет 600 посылок:

    80642=> BEGIN ISOLATION LEVEL REPEATABLE READ;
    BEGIN
    80642=*> UPDATE hubs SET packages_amount = packages_amount + 100 WHERE hub_id = 4 RETURNING packages_amount AS spb_amount_4;
    spb_amount_4
    --------------
    100
    (1 строка)

    UPDATE 1
    80642=*> SELECT * FROM hubs WHERE city = 'Санкт-Петербург';
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    3 | Санкт-Петербург | 500
    4 | Санкт-Петербург | 100
    (2 строки)
  2. Во втором сеансе начните транзакцию с уровнем изоляции Repeatable Read и посмотрите загруженность сортировочных центров в г. Санкт-Петербург:

    80667=> BEGIN ISOLATION LEVEL REPEATABLE READ;
    BEGIN
    80667=*> SELECT * FROM hubs WHERE city = 'Санкт-Петербург';
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    4 | Санкт-Петербург | 0
    3 | Санкт-Петербург | 500
    (2 строки)

    Вторая транзакция не видит изменений первой транзакции и полагает, что предельная суммарная емкость в 600 посылок еще не достигнута.

  3. Во втором сеансе добавьте 100 посылок в сортировочный центр в г. Санкт-Петербург (hub_id = 3).

    80667=*> UPDATE hubs SET packages_amount = packages_amount + 100 WHERE hub_id = 3 RETURNING packages_amount AS spb_amount_3;
    spb_amount_3
    --------------
    600
    (1 строка)

    UPDATE 1
    80667=*> SELECT * FROM hubs WHERE city = 'Санкт-Петербург';
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    4 | Санкт-Петербург | 0
    3 | Санкт-Петербург | 600
    (2 строки)
  4. В первом сеансе зафиксируйте транзакцию:

    80642=*> COMMIT;
    COMMIT
  5. Во втором сеансе зафиксируйте транзакцию:

    80667=*> COMMIT;
    COMMIT
  6. В первом сеансе посмотрите результат:

    80642=*> SELECT * FROM hubs WHERE city = 'Санкт-Петербург';
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    4 | Санкт-Петербург | 100
    3 | Санкт-Петербург | 600
    (2 строки)

    В результате нарушена предельная суммарная емкость сортировочных центров в г. Санкт-Петербург. Ошибка сериализации не возникла потому, что транзакции меняли разные строки. Такая аномалия называется несогласованной записью и допускается даже на уровне изоляции Repeatable Read.

Уровень изоляции Serializable​

Отсутствие аномалий​

  1. В первом сеансе восстановите количество посылок в сортировочных центрах г. Санкт-Петербург:

    80642=> UPDATE hubs SET packages_amount = packages_amount - 100 WHERE city = 'Санкт-Петербург';
    UPDATE 2
    80642=> SELECT * FROM hubs WHERE city = 'Санкт-Петербург';
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    4 | Санкт-Петербург | 0
    3 | Санкт-Петербург | 500
    (2 строки)
  2. В первом сеансе начните транзакцию с уровнем изоляции Serializable и добавьте 100 посылок в сортировочный центр в г. Санкт-Петербург (hub_id = 4) с условием того, что суммарная емкость сортировочных центров в г. Санкт-Петербург составляет 600 посылок:

    80642=> BEGIN ISOLATION LEVEL SERIALIZABLE;
    BEGIN
    80642=*> UPDATE hubs SET packages_amount = packages_amount + 100 WHERE hub_id = 4 RETURNING packages_amount AS spb_amount_4;
    spb_amount_4
    --------------
    100
    (1 строка)

    UPDATE 1
    80642=*> SELECT * FROM hubs WHERE city = 'Санкт-Петербург';
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    3 | Санкт-Петербург | 500
    4 | Санкт-Петербург | 100
    (2 строки)
  3. Во втором сеансе начните транзакцию с уровнем изоляции Serializable и посмотрите загруженность сортировочных центров в г. Санкт-Петербург:

    80667=> BEGIN ISOLATION LEVEL SERIALIZABLE;
    BEGIN
    80667=*> SELECT * FROM hubs WHERE city = 'Санкт-Петербург';
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    4 | Санкт-Петербург | 0
    3 | Санкт-Петербург | 500
    (2 строки)

    Вторая транзакция не видит изменений первой транзакции и полагает, что предельная суммарная емкость в 600 посылок еще не достигнута.

  4. Во втором сеансе добавьте 100 посылок в сортировочный центр в г. Санкт-Петербург (hub_id = 3).

    80667=*> UPDATE hubs SET packages_amount = packages_amount + 100 WHERE hub_id = 3 RETURNING packages_amount AS spb_amount_3;
    spb_amount_3
    --------------
    600
    (1 строка)

    UPDATE 1
    80667=*> SELECT * FROM hubs WHERE city = 'Санкт-Петербург';
    hub_id | city | packages_amount
    --------+-----------------+-----------------
    4 | Санкт-Петербург | 0
    3 | Санкт-Петербург | 600
    (2 строки)

    И в первой, и во второй транзакции условие предельной суммарной емкости не нарушено.

  5. В первом сеансе зафиксируйте транзакцию:

    80642=*> COMMIT;
    COMMIT
  6. Во втором сеансе зафиксируйте транзакцию:

    80667=*> COMMIT;
    ERROR: could not serialize access due to read/write dependencies among transactions
    ПОДРОБНОСТИ: Reason code: Canceled on identification as a pivot, during commit attempt.
    ПОДСКАЗКА: The transaction might succeed if retried.

    В результате выдана ошибка сериализации. Аномалия несогласованной записи не допускается на уровне изоляции Serializable, как и любые другие аномалии. Обратите внимание, что для применения уровня изоляции Serializable параллельные транзакции должны иметь тот же уровень изоляции. В противном случае будет применяться уровень изоляции Repeatable Read, несмотря на явное указание уровня Serializable.

Завершение​

  1. Завершите второй сеанс psql:

    80667=> \q
  2. В первом сеансе psql подключитесь к базе данных postgres:

    80642=> \c postgres
    Вы подключены к базе данных "postgres" как пользователь "student".
  3. Удалите базу данных delivery_db и завершите сеанс psql:

    135158=> drop database delivery_db;
    DROP DATABASE
    135158=> \q

Самопроверка​

Вопрос 1

Открыто два сеанса psql. Первый сеанс обслуживается процессом с pid=137455, второй — процессом с pid=137503. У каждого из сеансов в начале приглашения указывается pid обслуживающего процесса. В указанных сеансах последовательно выполняются следующие команды:

137455=> select * from some_table;
id | amount
----+--------
1 |     10
2 |     10
(2 строки)

137455=> BEGIN ISOLATION LEVEL REPEATABLE READ;
BEGIN

137503=> BEGIN ISOLATION LEVEL READ COMMITTED;
BEGIN

137455=*> UPDATE some_table SET amount = 15 WHERE id = 1;
UPDATE 1

137455=*> COMMIT;
COMMIT

137503=*> UPDATE some_table SET amount = 15 WHERE id = 2;
UPDATE 1

137503=*> SELECT sum(amount) FROM some_table;

Какое число будет получено в результате выполнения последнего запроса?

Вопрос 2

Открыто два сеанса psql. Первый сеанс обслуживается процессом с pid=137455, второй — процессом с pid=137503. У каждого из сеансов в начале приглашения указывается pid обслуживающего процесса. В указанных сеансах последовательно выполняются следующие команды:

137455=> select * from some_table;
id | amount
----+--------
1 |     10
2 |     10
(2 строки)

137455=> BEGIN ISOLATION LEVEL REPEATABLE READ;
BEGIN

137503=> BEGIN ISOLATION LEVEL READ COMMITTED;
BEGIN

137503=*> INSERT INTO some_table VALUES(3, 15)
UPDATE 1

137503=*> COMMIT;
COMMIT

137455=*> DELETE FROM some_table WHERE id = 1;

137455=*> SELECT sum(amount) FROM some_table;

Какое число будет получено в результате выполнения последнего запроса?

Вопрос 3

Какие ситуации из перечисленных могут возникать при использовании транзакций с уровнем изоляции Repeatable Read?

Вопрос 4

Открыто два сеанса psql. Первый сеанс обслуживается процессом с pid=137455, второй — процессом с pid=137503. У каждого из сеансов в начале приглашения указывается pid обслуживающего процесса. В указанных сеансах последовательно выполняются следующие команды:

137455=> BEGIN ISOLATION LEVEL SERIALIZABLE;
BEGIN

137455=*> SELECT * FROM some_table;
id | amount
----+--------
1 |     10
2 |     10
(2 строки)

137455=*> UPDATE some_table SET amount = 15 WHERE id = 1;
UPDATE 1

137503=> BEGIN ISOLATION LEVEL REPEATABLE READ;
BEGIN
137503=*> SELECT * FROM some_table;
id | amount
----+--------
2 |     10
1 |     10
(2 строки)

137503=*> UPDATE some_table SET amount = 15 WHERE id = 2;
UPDATE 1
137503=*> COMMIT;
COMMIT

137455=*> COMMIT;

Каким будет результат выполнения последней команды?