Я начинаю играть с PostgreSQL и замечаю, что sequence
никогда не откатывается, даже при неудачном INSERT
.
Я читал, что, как и ожидалось, будет предотвращено дублирование последовательностей в параллельных транзакциях, и я обнаружил, что это странно, поскольку мой опыт работы с базой данных только с GTM, где перезапуск транзакций является общим и используется именно для этого.Перезагрузка транзакции PostgreSQL
Так что я хотел проверить перезагружается в PGSQL и загружается это в базе данных:
CREATE SEQUENCE account_id_seq;
CREATE TABLE account
(
id integer NOT NULL DEFAULT nextval('account_id_seq'),
title character varying(40) NOT NULL,
balance integer NOT NULL DEFAULT 0,
CONSTRAINT account_pkey PRIMARY KEY (id)
);
INSERT INTO account (title) VALUES ('Test Account');
CREATE OR REPLACE FUNCTION mytest() RETURNS integer AS $$
DECLARE
cc integer;
BEGIN
cc := balance from account where id=1;
RAISE NOTICE 'Balance: %', cc;
perform pg_sleep(3);
update account set balance = cc+10 where id=1 RETURNING balance INTO cc;
return cc;
END
$$
LANGUAGE plpgsql;
Таким образом, функция mytest()
будет извлекать баланс, подождать 3 секунды (чтобы позволить мне запустить другой процесс), а затем обновить баланс на основе сохраненной переменной.
теперь запустить 2 вызова этой функции непосредственно из оболочки:
void$ psql -c "select * from account where id=1"
id | title | balance
----+--------------+---------
1 | Test Account | 0
(1 row)
void$ psql -c "select mytest()" & PIDA=$! && psql -c "select mytest()" && wait $PIDA
[1] 3312
NOTICE: Balance: 0
NOTICE: Balance: 0
mytest
--------
10
(1 row)
mytest
--------
10
(1 row)
[1]+ Done psql -c "select mytest()"
void$ psql -c "select * from account where id=1"
id | title | balance
----+--------------+---------
1 | Test Account | 10
(1 row)
я ожидал бы баланс, чтобы быть 20, а не 10, как последняя сделка будет совершено необходимо перезапустить в качестве «зрения» balance from account where id=1
изменено в процессе обработки ...
Я читал о transaction isolation in official documentation, и это кажется мне, что по умолчанию read committed
должно обеспечивать такое поведение точно ..
Я также испытанное изменяя уровень изоляции на serializable
, а затем последний Tran исправлено, но я хотел бы знать, нет ли какой-либо функции «перезагрузки транзакции» (как я описал), или если что-то не хватает ...
замки не точно так же, как и поведение я хотел/описал, но это была альтернатива, что я не знаю, как использовать и работает для моего дела, поэтому принято как ответ, спасибо! И я знаю, что я мог бы упростить его в одно обновление, но цель заключалась в том, чтобы легко протестировать это, чтобы увидеть, будет ли он «перезагружаться». –
С «перезагрузкой» я имел в виду, что вторая транзакция не дождалась завершения первой (например, LOCK в первой строке), но она будет выполняться, и только в части COMMIT она проверит, что «исходный вид БД» изменился и результаты были бы неожиданными, поэтому перезапуск с точки START TRANSACTION. –
Установка уровня изоляции транзакций на «serializable» делает это, но вместо перезапуска он выдает исключение. Я предполагаю, что я мог бы использовать функцию outter для этого исключения таким образом, чтобы она повторно выполняла внутреннюю функцию, пока она не выбросила ее, но на данный момент LOCK работают и даже кажутся лучшим решением для моего сценария. –