ПОДГОТОВИТЬ СДЕЛКУ Снятие замков?
Я должен что-то упустить из-за 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
все еще открыт, пока не будет зафиксирован или отменен.