2012-06-21 56 views
2

我一直在試圖解決Oracle在處理ROWNUMSELECT ... FOR UPDATE SKIP LOCKED時如何返回未鎖定的幾行的問題。我嘗試了以下幾個解決方案:Force Oracle to return TOP N rows with SKIP LOCKED,以及其他幾個與這個問題非常相似的例子。我知道Oracle AQ可能是最好的解決方案,但是我們對數據庫的控制很少,而且我遇到了相當大的阻力。如何從Oracle函數中鎖定並返回多行?

我遇到的問題是試圖使用JDBC將結果返回給Java。我試過setFetchSize(20),但遇到只有前20行分發給客戶端的問題。我通常會看到一個處理代理獲取所有20行或幾個處理器獲取某些行,所有這些行都加起來爲20.這非常類似於將ROWNUMSELECT ... FOR UPDATE SKIP LOCKED結合使用時看到的行爲。

最有前景的解決方案,我已經試過如下功能:

create type IND_ID as object 
(
    ID varchar2(200) 
); 

create type IND_ID_TABLE as table of IND_ID; 

create or replace function SELECTIDS return IND_ID_TABLE 
    pipelined is 

    ST_CURSOR SYS_REFCURSOR; 
    ID_REC IND_ID := IND_ID(null); 

begin 
    open ST_CURSOR for 
     select ID 
     from TABLE 
    /* where clause */ 
     for update SKIP LOCKED; 
    loop 
     fetch ST_CURSOR 
     into ID_REC.ID; 
     exit when ST_CURSOR%rowcount > 20 or ST_CURSOR%notfound; 
     pipe row(ID_REC); 
    end loop; 
    close ST_CURSOR; 
    return; 
end; 

然而,當我嘗試調用它像這樣:

select * from table(SELECTIDS) 

我得到一個ORA-14551: cannot perform a DML operation inside a query錯誤,我現在明白了是交易問題。刪除鎖定會導致函數返回行。

如何在保留鎖的同時將多行從此函數轉換爲JDBC?

+3

你可以使用一個ref cursor的參數嗎?或者是一個返回引用遊標的函數,我想。然後你會直接調用proc/function,而不是試圖在查詢中使用該函數。不確定是否可以避免這個問題,但可能會有所幫助。 –

+0

@AlexPoole根據你的建議,我能夠弄清楚如何至少取出一行,將其更改爲一個過程並使用OUT參數,並確保鎖定。我也發現了一些PEBKAC錯誤,我可能有一個替代解決方案工作。謝謝。 – atreides322

回答

-1

這不行。您調用一個pl/sql函數作爲select語句的一部分,並嘗試在該函數中啓動一個事務。我認爲這個錯誤很明顯。

+0

我明白錯誤在哪裏,我不知道如何完成我正在嘗試執行的操作,即客戶端鎖定並檢索當前未鎖定的前20行。不過,我想我已經想出了一個完全不同的解決方案,它可以做我需要的解決方案。我目前正在測試它。 – atreides322