2009-09-17 37 views
6

我們使用Spring SimpleJdbcCall調用Oracle中返回遊標的存儲過程。它看起來像SimpleJdbcCall沒有關閉遊標,並在一段時間後超過了最大打開遊標。ORA-01000:使用Spring時超出最大打開遊標SimpleJDBCCall

ORA-01000: maximum open cursors exceeded ; nested exception is java.sql.SQLException: ORA-01000: maximum open cursors exceeded spring 

還有一些人在論壇上經歷過這個但看似沒有答案的人。它看起來像是spring/oracle支持中的一個bug。

這個bug很重要,可能會影響我們將來使用Spring JDBC。

是否有人遇到過修復 - 要麼將問題跟蹤到Spring代碼,要麼找到避免問題的解決方法?

我們使用Spring 2.5.6。

下面是使用SimpleJdbcCall時這似乎無法正確關閉結果集通過遊標PROC返回代碼的新版本:

... 
SimpleJdbcCall call = new SimpleJdbcCall(dataSource); 

Map params = new HashMap(); 
params.put("remote_user", session.getAttribute("cas_username")); 

Map result = call 
    .withSchemaName("urs") 
    .withCatalogName("ursWeb") 
    .withProcedureName("get_roles") 
    .returningResultSet("rolesCur", new au.edu.une.common.util.ParameterizedMapRowMapper()) 
    .execute(params); 
List roles = (List)result.get("rolesCur") 

老版本的代碼不使用Spring JDBC沒有這個問題:

oracleConnection = dataSource.getConnection(); 
callable = oracleConnection.prepareCall(
     "{ call urs.ursweb.get_roles(?, ?) }" ); 
callable.setString(1, (String)session.getAttribute("cas_username")); 
callable.registerOutParameter (2, oracle.jdbc.OracleTypes.CURSOR); 
callable.execute(); 
ResultSet rset = (ResultSet)callable.getObject(2); 
... do stuff with the result set 
if (rset != null) rset.close(); // Explicitly close the resultset 
if (callable != null) callable.close(); //Close the callable 
if (oracleConnection != null) oracleConnection.close(); //Close the connection 

看來Spring JDBC並沒有調用rset.close()。如果我在舊代碼中註釋掉那行,那麼在加載測試後,我們會得到相同的數據庫異常。

+3

請張貼一些代碼,顯示您如何使用SimpleJdbcCall。這很可能不是Spring中的錯誤,更可能是您使用它的方式,特別是考慮到Oracle處理結果集的非標準方式。 – skaffman 2009-09-17 08:55:32

+1

+1與skaffman。如果你找不到問題,可以嘗試構建一個堅如磐石的測試用例,以在http://jira.springframework.org/上報告錯誤。 – 2009-09-17 15:02:27

回答

7

經過多次測試,我們已經解決了這個問題。它是我們如何使用spring框架和oracle客戶端以及oracle數據庫的組合。我們正在創建新的SimpleJDBCCalls,它們使用Oracle JDBC客戶端的元數據調用,這些調用作爲未被關閉並清理的遊標返回。我認爲這是Spring JDBC框架中它調用元數據的一個錯誤,但不會關閉遊標。 Spring應該將元數據從光標中複製出來並正確關閉。我一直沒有打開彈簧jira問題,因爲如果你使用最佳做法,該錯誤不會展出。

調整OPEN_CURSORS或任何其他參數是解決此問題的錯誤方法,只是延遲它的出現。

我們通過將SimpleJDBCCall移動到一個單獨的DAO中來解決它/修復了這個問題,因此只有一個遊標爲我們調用的每個oracle proc打開。這些遊標在應用程序的整個生命週期中都是開放的 - 我認爲這是一個錯誤。只要OPEN_CURSORS大於SimpleJDBCCall對象的數量,那麼就不會有麻煩。

+5

我希望你報告這個,如果你認爲它是一個錯誤:) – 2009-11-04 23:02:30

1

我可以向你保證它不是Spring。我從事的是2005年推出的Spring 1.x應用程序,並且自此以後就沒有泄露過連接。 (WebLogic 9.,JDK 5)。你沒有正確地關閉你的資源。

您使用連接池嗎?你正在部署哪個應用程序服務器?哪個版本的Spring?甲骨文? Java的?詳細信息,請。

-3

的解決方案是不是在春天,但在甲骨文:您需要將OPEN_CURSORS初始化參數設置爲某個值高於默認的50

甲骨文 - 至少-8I的,也許它已經改變 - - 將重新解析JDBC PreparedStatement對象,除非將它們保留爲打開狀態。這很昂貴,而且大多數人最終都會維持一個固定的重新提交的開放語句池。

(採取快速瀏覽一下10i的文檔,他們明確指出OCI驅動程序將緩存的PreparedStatement,所以我假設本地驅動程序還是重新創建它們每次)

+2

這是資源泄漏,資源泄漏的解決方案是停止漏水,不加水。 – 2012-06-27 01:27:23

+1

@Andrew - 感謝您的評價以及您的downvote。但是,自從20世紀90年代初期與甲骨文合作以來,我堅持我的回答。開箱即用,其配置不適合複雜的應用程序。而且,OP使用的是Spring,它在清理後非常好。 OP仍然有可能在某處寫入了資源泄漏,但與他/她進行明確的連接管理相比,其可能性要低得多。 – kdgregory 2012-06-30 12:12:30

+0

重讀所有帖子,我發現OP在我的回覆後兩個月發佈了接受的答案,表明它實際上是Spring的資源泄漏。然而,假設所謂的泄漏是Spring試圖緩存元數據,我會參考我的第二段,並且仍然支持這個答案。 – kdgregory 2012-06-30 12:15:52

-2

甲骨文OPEN_CURSORS是關鍵好嗎。我們有一個全天候運行的小型24x7應用程序,只有一些顯然是開放的遊標。直到我們將OPEN_CURSORS初始化值設置爲> 300時,我們有間歇性的最大打開遊標錯誤。

+4

這是資源泄漏,資源泄漏的解決方案是停止泄漏,不添加更多水。 – 2012-06-27 01:27:34

2

只需謹慎地將OPEN_CURSORS設置爲更高和更高的值,因爲有開銷,並且它可能只是對實際問題/錯誤你的代碼。

我沒有與這個彈簧側的經驗,但在一個應用程序,我們有許多問題與ORA-01000錯誤的工作,並不斷調整OPEN_CURSORS剛纔提出的問題消失了一小會兒......

3

嗯,我在閱讀BLOB時遇到了這個問題。主要原因是我也在更新表,並且包含update語句的Statement沒有自動關閉。討厭的cursorleak吃所有免費的遊標。在顯式調用statement.close()之後,錯誤消失。

道德 - 總是關閉所有的東西,配置語句後不要靠自動關閉。

相關問題