如何在循环中使用异常处理,使循环不会在PostgreSQL中中断

ruarlubt  于 2023-06-22  发布在  PostgreSQL
关注(0)|答案(1)|浏览(156)

我有一个postgres函数,我想在循环中处理异常并继续。然而,这对于正常情况下工作正常。在扩展和测试时,它最终会陷入死锁。我假设这是因为www.example.com内部有多个事务function.is没有多个begin-end的方法可以解决这个问题。

CREATE OR REPLACE FUNCTION get_or_create_abc
    input_dict json)
    RETURNS TABLE(success_list text[], failed_list text[]) 
    LANGUAGE 'plpgsql'

AS $BODY$
DECLARE
....

BEGIN
    
    FOR key, value IN SELECT * FROM json_each(input_dict)
    LOOP
    FOR row IN SELECT json_array_elements(value)
    LOOP
    BEGIN
    a := row->>0;
    x := row->>1;
    y := row->>2;
    z := row->>3;
    counter = 0 ;
    WHILE counter < 3 LOOP
    BEGIN
    // functions//
    EXIT;
    EXCEPTION
      WHEN UNIQUE_VIOLATION THEN
       GET STACKED DIAGNOSTICS constraint_name_ := CONSTRAINT_NAME;
       IF constraint_name_ = abc THEN
        //..//
       ELSIF constraint_name_ = cde THEN
        //..// 
        exit;
       ELSE
         RAISE;
       END IF;

END;
END LOOP;
END;
end loop;
END LOOP;
    //...//
 RETURN query select success_list,failed_list;
 EXCEPTION
 WHEN OTHERS THEN
   //...//
END;
$BODY$;

ALTER FUNCTION protecto_vault.get_or_create_tokens(json)
    OWNER TO test_user;
vfhzx4xs

vfhzx4xs1#

看起来有可能重写它,这样你就不需要一个循环了。循环可能会很慢,我猜如果你的update/insert在几个语句中运行,它会更快,这可能会防止死锁。
我建议将您的数据批处理到可以同时处理的逻辑组中,类似于此。

select (exjs ->> 'col1') :: bigint as a,
           (exjs ->> 'col2') :: bigint as x,
           (exjs ->> 'col3') :: int    as y,
           (exjs ->> 'col4') :: date   as z
    from jsonb_array_elements(:your_data) exjs --expanded js
), first_insert as (
insert into some.table(a, x, y, z)
select
    d.a,
    d.x,
    d.y,
    d.z
from data d
where not exists(
    select
        from some.table s
        where s.a = d.a --Ensure that no exceptions will happen when inserting/updating/deleting or whatever you are doing
)
), constraint_handling as (
--     Now handle all the rows that would have hit the exception
    select
        from data d
        where exists (
            select
                from some.table s
                where s.a = d.a
        )
)
select true as finished
;

如果在这样的更新过程中仍然存在命中约束的问题,那么可以考虑将约束检查推迟到事务结束时进行。
例如

set constraints your.constraint_name deferred;
--run update
set constraints your.constraint_name immediate;

请注意,这仅在将约束创建为可延迟时有效。例如

alter table your.table
      add constraint fk_your_key unique (id) deferrable initially immediate;

请参阅Postgresql手册了解有关可延期约束的更多信息。

相关问题