隔离级别可序列化锁定 postgresql 9.6

ISOLATION LEVEL SERIALIZABLE locking postgresql 9.6

DO $$
BEGIN
raise notice '%', (SELECT * from public.clientcalledthisfunction(1,2));
END $$;

CREATE OR REPLACE FUNCTION  public.clientcalledthisfunction(userid1_ integer, userid2_ integer)
RETURNS integer
AS $$
DECLARE
result integer;
BEGIN
result:=(SELECT  * from public.call_updatedata(userid1_, userid2_)) ;
RETURN result;
EXCEPTION WHEN others THEN
End $$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION public.call_updatedata(userid1_ integer, userid2_ integer)
RETURNS integer
AS $$
DECLARE
userdata_1 integer;
userdata_2 integer;
userdata_total integer;
BEGIN

SELECT * FROM public.updatedata(userid1_) INTO userdata_1;

SELECT * FROM public.updatedata(userid2_) INTO userdata_2;

userdata_total:=(userdata_1 + userdata_2);
RETURN userdata_total;
EXCEPTION WHEN others THEN
End $$ LANGUAGE plpgsql;


CREATE OR REPLACE FUNCTION public.updatedata(userid_ integer)
RETURNS integer
AS $$
DECLARE
userdata_ integer;
BEGIN

LOOP
SET  TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN
SAVEPOINT foo;

SELECT userdata FROM public.footable WHERE userid=userid_ INTO userdata_;

UPDATE public.footable SET userdata = userdata_ + 1 WHERE userid=userid_ ;

EXIT ;
EXCEPTION WHEN others THEN
    ROLLBACK TO SAVEPOINT foo;
END;
END LOOP;
RETURN userdata_ + 1;
EXCEPTION WHEN others THEN
END $$ language plpgsql;

客户端calls public.clientcalledthisfunction()函数;

我需要在 updatedata() 函数的 SELECT + UPDATE 上实现 ISOLATION LEVEL SERIALIZABLE,因为我不想 "lost update"...我想设置 SERIALIZABLE 隔离级别 只有 public.updatedata function()

而在updatedata()函数中如果有异常;我希望它回滚到 savepoint foo 并重试 select + update 再次循环处理...

但是我 error"control reached end of function without RETURN"...我不明白问题出在哪里。

在每个函数中你都有

EXCEPTION WHEN others THEN
End

最后。如果发生任何异常,则会触发这段代码。由于之后没有 return 语句,它会因 "control reached end of function without RETURN" 错误而崩溃。

分析那些异常,你就知道到底是怎么回事了。或者甚至更好,只需删除这些行。毕竟EXCEPTION WHEN others是万恶之源


编辑: 经过一番搜索,您似乎无法在函数内更改隔离级别。毕竟调用函数是一个查询,必须在任何查询之前设置隔离级别。

I want to set SERIALIZABLE isolation level only in public.updatedata function().

你不能。隔离是事务级的 属性.

And in updatedata() function if there is an exception; i want it to rollback to savepoint foo

您可以为此使用 BEGIN ... EXCEPTION ... 块。

但如果您使用可序列化隔离,这实际上不会起作用,因为某些序列化失败只能在提交时发现。