holdable模式可以使當前游標不被立即釋放,從而實現游標跨事務操作。本文介紹如何在存儲過程中使用holdable cursor。

背景信息

在存儲過程中使用動態游標時,PostgreSQL原生不支持將動態游標設置為holdable模式(非存儲過程中支持),如果在存儲過程中打開一個動態游標并執行事務修改保存操作后,再次嘗試獲取數據將會報錯,因為進行事務保存操作時當前事務中的游標將會被釋放。

因此PolarDB PostgreSQL版(兼容Oracle)為了滿足用戶需求,支持在PLSQL中使用holdable模式打開存儲過程游標。

PostgreSQL原生一類典型的出錯場景如下:
CREATE TABLE test001(id numeric);
INSERT INTO test001 VALUES (1), (2), (3);
CREATE OR REPLACE PROCEDURE testcur_001
IS
    DECLARE
        myref1 refcursor;
        i numeric;
    BEGIN
        OPEN myref1 FOR SELECT * from test001;
        commit;
        fetch myref1 into i;
        dbms_output.put_line(i);
        close myref1;
    END;

EXEC testcur_001;
DROP TABLE test001;
顯示結果如下:
ERROR:  cursor "myref1" does not exist  
CONTEXT:  polar-spl function testcur_001() line 8 at FETCH
說明 報錯,因為myref1在commit后被自動釋放,故顯示游標myref1不存在。

使用指南

  • 設置允許單個游標跨事務

    在PLSQL中使用holdable模式打開單個游標的具體語法為:在OPEN語句中FOR前加關鍵字HOLD

    具體示例如下:
    CREATE TABLE test001(id numeric);
    
    INSERT INTO test001 VALUES (1), (2), (3);
    
    CREATE OR REPLACE PROCEDURE testcur_001
    IS
        DECLARE
            myref1 refcursor;
            i numeric;
        BEGIN
            OPEN myref1 HOLD FOR SELECT * from test001;
            commit;
            fetch myref1 into i;
            dbms_output.put_line(i);
            close myref1;
        END;
    
    EXEC testcur_001;
    
    DROP TABLE test001;
    說明 在PLSQL中使用holdable模式打開單個游標的具體語句如下:
    OPEN cursorname HOLD FOR SELECT ...
    顯示結果如下:
    POLAR-SPL Procedure successfully completed       
    說明 加關鍵字HOLD后,顯示POLAR-SPL程序執行成功。
  • 設置允許所有游標跨事務

    您需要在控制臺開啟polar_plsql_enable_holdable_refcursor參數,使您可以使用holdable模式打開所有游標。

    說明
    • 該參數修改不需要重啟數據庫,但只對新連接生效。若您使用長連接建議修改后自行選擇時間重啟。
    • 該參數默認關閉。
    • 開啟后將自動將所有存儲過程中的游標設置為HOLD模式,包括顯式游標和游標變量。
    • 事務塊中游標不受影響。
  • 使用HOLD模式的動態游標時,請確保在當前存儲過程結束前使用close語句顯式關閉該游標。
  • HOLD模式下的動態游標即使存儲過程結束也不會自動釋放,其消耗的內存與游標返回的查詢條目數量相關,部分情況下會寫入臨時文件。
  • 大量使用HOLD而不關閉會對內存帶來顯著壓力,造成臨時文件堆積,也有可能導致后續的讀取數據操作變慢。