天天看點

【DB吐槽大會】第67期 - PG 存儲過程和函數内對自治事務支援不完整

背景

1、産品的問題點

  • PG 存儲過程和函數内對自治事務支援不完整

2、問題點背後涉及的技術原理

  • PG 的1個函數為1個原子操作, 要麼全部復原, 要麼全部失敗. (注意: exception裡算一個新事務, 觸發exception時, 函數體内的操作全部復原, exception體内的執行如果正常則這個exception體内的變更操作可以送出.)
  • 在函數内不能使用commit, rollback, savepoint等事務控制語句.
  • 在存儲過程中隻能使用commit, rollback事務控制語句, 不能使用savepoint, rollback to savepoint, release savepoint等語句.

3、這個問題将影響哪些行業以及業務場景

  • 使用function, procedure進行複雜業務邏輯處理的場景, 例如分析業務, 報表業務等

4、會導緻什麼問題?

  • 無法靈活的處理事務控制

5、業務上應該如何避免這個坑

  • 暫時沒有很好的解決方案, 一些類似的替代方案, 都非常難操作

使用exception也很難滿足, 如下, 使用變量、exception 來模拟savepoint和rollback to savepoint的功能, 也很複雜 :

create or replace procedure p (int, int) as $$  
declare  
  v int := $1;  
  retris int := $2;  
  text_var1 text;  
  text_var2 text;  
  text_var3 text;  
  text_var4 text;  
begin  
  if retris >= 3 then   
    raise notice 'retris: %', retris;   
    return;   
  end if;    
    
  if v = 0 then  
    v := 1;  
    insert into a values (1);   
    commit;  
  end if;  
    
  if v = 1 then   
    v := 2;  
    insert into a values (2);  
    commit;  
  end if;   
  
  if v = 2 then   
    v := 3;   
    insert into a values (3);   
    commit;   
  end if;   
  
  if v = 3 then   
    v := 4;   
    insert into a values (4);   
    commit;   
  end if;   
  
exception when others then   
  GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT,  
                          text_var2 = PG_EXCEPTION_DETAIL,  
                          text_var3 = PG_EXCEPTION_HINT,  
                          text_var4 = PG_EXCEPTION_CONTEXT;  
                          raise notice '%,%,%,%', text_var1, text_var2, text_var3, text_var4;  
  commit;  
  call p(v-1, retris+1) ;   
end;   
$$ language plpgsql;   
  
  
  
postgres=# \set VERBOSITY verbose  
postgres=# call p (0,0);  
NOTICE:  00000: cannot commit while a subtransaction is active,,,PL/pgSQL function p(integer,integer) line 18 at COMMIT  
LOCATION:  exec_stmt_raise, pl_exec.c:3906  
NOTICE:  00000: cannot commit while a subtransaction is active,,,PL/pgSQL function p(integer,integer) line 18 at COMMIT  
SQL statement "call p(v-1, retris+1)"  
PL/pgSQL function p(integer,integer) line 45 at CALL  
LOCATION:  exec_stmt_raise, pl_exec.c:3906  
NOTICE:  00000: cannot commit while a subtransaction is active,,,PL/pgSQL function p(integer,integer) line 18 at COMMIT  
SQL statement "call p(v-1, retris+1)"  
PL/pgSQL function p(integer,integer) line 45 at CALL  
SQL statement "call p(v-1, retris+1)"  
PL/pgSQL function p(integer,integer) line 45 at CALL  
LOCATION:  exec_stmt_raise, pl_exec.c:3906  
NOTICE:  00000: retris: 3  
LOCATION:  exec_stmt_raise, pl_exec.c:3906  
CALL  
  
  
  
通過dblink去調用p(int,int), 開啟一個新會話是可以的. 複雜度又增加了.          

6、業務上避免這個坑犧牲了什麼, 會引入什麼新的問題

  • 開發門檻非常高.

7、資料庫未來産品疊代如何修複這個坑

  • 希望在函數、存儲過程中實作完整的事務控制邏輯. 包括begin;end;savepoint;rollback;commit;release savepoint;rollback to savepoint;等