ПОДГОТОВИТЬ СДЕЛКУ Снятие замков?

Я должен что-то упустить из-за PostgreSQL и двухфазного коммита с PREPARE TRANSACTION.

Следующий SQL:

BEGIN; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1

Дает следующие блокировки:

4092    Private 329373  acc     15/53295    RowExclusiveLock    Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1    
4092    Private 329369  acc     15/53295    RowExclusiveLock    Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1    
4092    Private 328704  acc     15/53295    RowExclusiveLock    Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1    
4092    Private 327169  acc     15/53295    RowExclusiveLock    Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1    
4092            acc 15/53295    15/53295    ExclusiveLock   Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1    
4092    Private 329377  acc     15/53295    RowExclusiveLock    Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1    
4092            acc     15/53295    ExclusiveLock   Oui 2013-06-13 18:15:55+02  UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1

Как только сделка подготовлена:

PREPARE TRANSACTION 'TEST'

замок исчез.

Поскольку между PREPARE и COMMIT возникает небольшая задержка, другой запрос может получить более старую версию записи.

Есть ли настройки конфигурации, чтобы избежать такого поведения, или это сделано специально?

Заранее спасибо.

РЕДАКТИРОВАТЬ: я использую PostgreSQL 9.2.2 на Windows x64 (PostgreSQL 9.2.2, скомпилированная в Visual C++ build 1600, 64-разрядная версия)

РЕДАКТИРОВАТЬ 2: Ниже приводится полный тестовый пример:

Введите следующее в новом сеансе:

BEGIN; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
UPDATE person.tcities set ctyname='L ABERGEMENT CLEMENCIAT TRANSACT' WHERE ctyid = 1
PREPARE TRANSACTION 'TEST';

Тогда в другой новой сессии:

SELECT * FROM person.tcities

Вы получите старую версию записей.

1 ответ

Решение

Я не могу воспроизвести описанное поведение на PostgreSQL 9.2:

 CREATE TABLE prep_test AS SELECT generate_series(1,10) AS x;

 BEGIN;
 UPDATE prep_test SET x = x*10;
 PREPARE TRANSACTION 'test';

затем во второй сессии:

 UPDATE prep_test SET x = x*20;

блоки, как и ожидалось, пока я либо COMMIT PREPARED 'test' или же ROLLBACK PREPARED 'test'

Я также получил ожидаемые результаты при тестировании сериализуемой изоляции:

A# BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
B# BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
A# INSERT INTO prep_test(x) VALUES (42);
B# INSERT INTO prep_test(x) VALUES (43);
A# SELECT count(x) FROM prep_test;
B# SELECT count(x) FROM prep_test;
A# PREPARE TRANSACTION 'test';
B# COMMIT;

B терпит неудачу с ошибкой сериализуемости, точно как ожидалось. То же самое происходит, если B пытается PREPARE TRANSACTION тоже.

После того, как вопрос обновлен тестовым примером

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

PREPARE TRANSACTION не коммит Вы все еще можете ROLLBACK PREPARED, Таким образом, PostgreSQL не может показать вам измененные строки, пока вы не сделаете финальный COMMIT PREPARED иначе вы получите грязную аномалию чтения, если вы прочитаете строки, а затем сделали ROLLBACK PREPARED,

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

Если обе транзакции SERIALIZABLE тогда все еще в порядке. Сериализуемость требует наличия действительного порядка, в котором параллельные транзакции могли бы происходить последовательно для получения одинаковых результатов. Здесь это очевидно: SELECT пришел первым, потом UPDATE, Транзакции по- прежнему происходят одновременно друг с другом, когда SELECT происходит из-за транзакции, подготовленной с PREPARE TRANSACTION все еще открыт, пока не будет зафиксирован или отменен.

Другие вопросы по тегам