【问题标题】:ISOLATION LEVEL SERIALIZABLE locking postgresql 9.6隔离级别可序列化锁定 postgresql 9.6
【发布时间】:2017-01-06 09:48:58
【问题描述】:
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,因为我不想“丢失更新”...我想在public.updatedata function() 中设置SERIALIZABLE 隔离级别 .

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

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

【问题讨论】:

    标签: postgresql isolation-level postgresql-9.6


    【解决方案1】:

    我只想在 public.updatedata function() 中设置 SERIALIZABLE 隔离级别。

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

    并且在updatedata()函数中如果有异常;我希望它回滚到保存点 foo

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

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

    【讨论】:

    • ....“但是,如果您使用可序列化隔离,这实际上不起作用,因为某些序列化失败只能在提交时发现。”......没有其他方法可以做这个?我的意思是变通?
    • @sommeguyy 你没有清楚地解释你要解决的根本问题,所以很难说。
    • 最终我通过使用“FOR UPDATE”锁解决了我的问题。
    【解决方案2】:

    在你拥有的每一个功能中

    EXCEPTION WHEN others THEN
    End
    

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

    分析这些异常,您将确切知道发生了什么。或者更好的是,只需删除这些行。毕竟EXCEPTION WHEN others是万恶之源。


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

    【讨论】:

    • 如果我按照你的说法删除它,那么它会给出一个错误消息“必须在任何查询之前调用 SET TRANSACTION ISOLATION LEVEL”
    • @sommeguyy 给你。你有 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 内循环。我认为如果你把它移到外面(即 1 条线)那么它应该没问题。
    • @sommeguyy 对,经过一番搜索,您似乎无法更改函数内部的隔离级别。请阅读:stackoverflow.com/questions/6274457/… 毕竟调用函数已经是一个查询。
    猜你喜欢
    • 1970-01-01
    • 2021-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-06
    • 2020-07-16
    • 1970-01-01
    相关资源
    最近更新 更多