Код: Выделить всё
set define off;
CREATE TABLE hr.t1 (c1 NUMBER PRIMARY KEY, c2 VARCHAR2(50));
INSERT INTO hr.t1 (c1) VALUES(1);
INSERT INTO hr.t1 (c1) VALUES(2);
CREATE OR REPLACE EDITIONABLE PROCEDURE "HR"."DEADLOCK_EX1" IS
deadlock EXCEPTION;
PRAGMA EXCEPTION_INIT(deadlock,-60);
BEGIN
UPDATE t1 SET c2 = 'str 1, session 1' where c1=1;
dbms_output.put_line(sysdate);
dbms_lock.sleep(30);
insert into t1 values(3,'str 3, session 1'); --- test case
dbms_lock.sleep(30);
UPDATE t1 SET c2 = 'str 2, session 1' where c1=2;
COMMIT;
EXCEPTION WHEN deadlock then commit;
END;
/
create or replace PROCEDURE deadlock_ex2 IS
deadlock EXCEPTION;
PRAGMA EXCEPTION_INIT(deadlock,-60);
BEGIN
UPDATE t1 SET c2 = 'str 2, session 2' where c1=2;
insert into t1 values(4,'str 4, session 2'); --- test case
UPDATE t1 SET c2 = 'str 1, session 2' where c1=1;
COMMIT;
EXCEPTION WHEN deadlock then commit; -- without exception - commit for all block
END;
и когда deadlock происходит, оказываются зафиксированными все записи в двух процедурах,
какие они сделали. То есть в одной сессии запускаем одну процедуру, в другой другую,
данные фиксируется для двух сессий после дедлока (на момент исключения).
Код: Выделить всё
CREATE OR REPLACE PROCEDURE hr.DEADLOCK_EX3()
LANGUAGE plpgsql
AS $$
BEGIN
BEGIN
--- SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
UPDATE hr.T1 SET C2 = 'str 1, session 1' where C1 = 1;
RAISE NOTICE '%',LOCALTIMESTAMP;
PERFORM pg_sleep(30);
insert into hr.T1 values(3,'str 3, session 1'); --- test case
PERFORM pg_sleep(30);
UPDATE hr.T1 SET C2 = 'str 2, session 1' where C1 = 2;
-- COMMIT
-- RETURN;
-- COMMIT;
EXCEPTION WHEN deadlock_detected then
COMMIT; -- COMMIT
END;
-- without exception - commit for all block
END; $$;
CREATE OR REPLACE PROCEDURE hr.DEADLOCK_EX4()
LANGUAGE plpgsql
AS $$
BEGIN
-- SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN
UPDATE hr.T1 SET C2 = 'str 2, session 2' where C1 = 2;
insert into hr.T1 values(4,'str 4, session 2'); --- test case
UPDATE hr.T1 SET C2 = 'str 1, session 2' where C1 = 1;
-- COMMIT;
--RETURN;
EXCEPTION WHEN deadlock_detected then
COMMIT; -- COMMIT
-- without exception - commit for all block
END;
END; $$;
\set ON_ERROR_ROLLBACK off
так и без него.
В случае с PostgreSQL коммит случается только для одной сессии, а не для двух, если запустить эти две процедуры одновременно в двух сессиях и поймать deadlock.
Вопрос такой:
следует ли вообще пытаться управлять в PostgreSQL системными исключениями по типу deadlock через deadlock_detected и подобное? Или
следует искать обходное решение, то есть ловить системное исключение вручную, например, через системное ожидание?