Это вопрос о последующих действиях от этого one, поэтому я знаю, что могу использовать (блокирование) LOCK, но я хочу использовать блокировки предикатов и сериализуемую изоляцию транзакций.Generic обработчик PostgreSQL для сбоя сериализации
То, что я хотел бы иметь, является общим обработчиком сбоев сериализации, которые будут повторять функцию/запрос X раз.
В качестве примера, у меня есть это:
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;
CREATE OR REPLACE FUNCTION myretest() RETURNS integer AS $$
DECLARE
tries integer := 5;
BEGIN
WHILE TRUE LOOP
BEGIN -- nested block for exception
RETURN mytest();
EXCEPTION
WHEN SQLSTATE '40001' THEN
IF tries > 0 THEN
tries := tries - 1;
RAISE NOTICE 'Restart! % left', tries;
ELSE
RAISE EXCEPTION 'NO RESTARTS LEFT';
END IF;
END;
END LOOP;
END
$$
LANGUAGE plpgsql;
Таким образом, если вызов mytest()
непосредственно параллельно я получаю отказ сериализации на последней фиксации:
4SO$ psql -c "select mytest()" & PIDA=$! && psql -c "select mytest()" && wait $PIDA
[1] 4909
NOTICE: Balance: 0
NOTICE: Balance: 0
mytest
--------
10
(1 row)
ERROR: could not serialize access due to concurrent update
CONTEXT: SQL statement "update account set balance = cc+10 where id=1 RETURNING balance"
PL/pgSQL function mytest() line 10 at SQL statement
Если я позвоню myretest()
он должен попытаться выполнить mytest()
до 5-й попытки, где он будет поднимать исключение.
Так у меня есть две точки здесь (где, возможно, пункт 2 также аннулирует пункт 1):
myretest()
не работает, как и ожидалось, каждые результаты итерации исключением serialiation_failure даже после приуроченных отделки резьбы: есть ли что я должен добавить для «перезагрузки» транзакции?Как я могу сделать это (
myretest()
логика) общим, чтобы он применим к каждой вызываемой функции в системе без необходимости использовать функции «обертки»?