java中sql去除游标_java.sql.SQLException:-ORA-01000:已超过最大打开游标
小編典典
ORA-01000(最大打開游標錯誤)是Oracle數據庫開發中極為常見的錯誤。在Java上下文中,當應用程序嘗試打開比數據庫實例上配置的游標更多的ResultSet時,就會發生這種情況。
常見原因有:
配置錯誤
在應用程序中,查詢數據庫的線程比數據庫中的游標的線程更多。一種情況是你的連接和線程池大于數據庫上的游標數。
你有許多開發人員或應用程序連接到同一個數據庫實例(可能包含許多架構),并且一起使用的連接過多。
解:
增加數據庫上的游標數量(如果資源允許)或
減少應用程序中的線程數。
游標泄漏
應用程序未關閉ResultSet(在JDBC中)或游標(在數據庫上的存儲過程中)
解決方案:游標泄漏是錯誤;增加數據庫上的游標數量只會延遲不可避免的故障。可以使用靜態代碼分析,JDBC或應用程序級日志記錄以及數據庫監視來發現泄漏。
背景
本節描述了游標背后的一些理論以及應如何使用JDBC。如果你不需要了解背景,可以跳過此步驟,直接進入“消除泄漏”。
什么是游標?
游標是數據庫上的資源,用于保存查詢的狀態,特別是讀取器在ResultSet中的位置。每個SELECT語句都有一個游標,并且PL / SQL存儲過程可以打開并根據需要使用任意數量的游標。你可以在Orafaq上找到有關游標的更多信息。
數據庫實例通常服務于幾種不同的模式,許多不同的用戶各自具有多個會話。為此,它具有可用于所有模式,用戶和會話的固定數量的游標。當所有游標都處于打開狀態(使用中)并且要求新游標的請求進入時,請求失敗,并出現ORA-010000錯誤。
查找和設置光標數量
該號碼通常由DBA在安裝時配置。可以在Oracle SQL Developer的管理員功能中訪問當前使用的游標數量,最大數量和配置。在SQL中,可以使用以下命令進行設置:
ALTER SYSTEM SET OPEN_CURSORS=1337 SID='*' SCOPE=BOTH;
將JVM中的JDBC與數據庫上的游標相關聯
下面的JDBC對象與以下數據庫概念緊密相關:
JDBC 連接是數據庫會話的客戶端表示形式,并提供數據庫事務。一個連接一次只能打開一個事務(但是事務可以嵌套)
數據庫上的單個游標支持JDBC ResultSet。在ResultSet上調用close()時,將釋放光標。
JDBC CallableStatement調用數據庫上的存儲過程,通常以PL / SQL編寫。該存儲過程可以創建零個或多個游標,并且可以將游標作為JDBC ResultSet返回。
JDBC是線程安全的:在線程之間傳遞各種JDBC對象是完全可以的。
例如,你可以在一個線程中創建連接。另一個線程可以使用此連接來創建PreparedStatement,第三個線程可以處理結果集。唯一的主要限制是,你隨時都不能在一個PreparedStatement上打開多個ResultSet。請參見Oracle DB每個連接是否支持多個(并行)操作?
請注意,數據庫提交發生在連接上,因此該連接上的所有DML(INSERT,UPDATE和DELETE)都將一起提交。因此,如果要同時支持多個事務,則每個并發事務必須至少具有一個Connection。
關閉JDBC對象
執行ResultSet的典型示例是:
Statement stmt = conn.createStatement();
try {
ResultSet rs = stmt.executeQuery( "SELECT FULL_NAME FROM EMP" );
try {
while ( rs.next() ) {
System.out.println( "Name: " + rs.getString("FULL_NAME") );
}
} finally {
try { rs.close(); } catch (Exception ignore) { }
}
} finally {
try { stmt.close(); } catch (Exception ignore) { }
}
請注意,finally子句如何忽略close()引發的任何異常:
如果你只關閉ResultSet而沒有使用try {} catch {},則它可能會失敗并阻止Statement被關閉
我們希望允許嘗試主體中引發的任何異常傳播到調用方。如果有一個循環,例如創建和執行語句,請記住關閉循環中的每個語句。
在Java 7中,Oracle引入了AutoCloseable接口,該接口用一些漂亮的語法糖代替了大多數Java 6樣板。
持有JDBC對象
JDBC對象可以安全地保存在局部變量,對象實例和類成員中。通常更好的做法是:
使用對象實例或類成員來保存可以在更長的時間內多次重用的JDBC對象,例如Connections和PreparedStatements
將局部變量用于ResultSet,因為通常會在單個函數范圍內獲取,循環并關閉它們。
但是,有一個例外:如果你正在使用EJB或Servlet / JSP容器,則必須遵循嚴格的線程模型:
只有Application Server創建線程(用于處理傳入請求)
只有Application Server創建連接(你可以從連接池中獲得)
在兩次調用之間保存值(狀態)時,必須非常小心。永遠不要將值存儲在你自己的緩存或靜態成員中-這在群集和其他怪異條件下并不安全,并且Application Server可能會對你的數據造成可怕的后果。而是使用有狀態Bean或數據庫。
特別是,永遠不要通過不同的遠程調用來保存JDBC對象(連接,結果集,PreparedStatements等)-讓Application Server對此進行管理。Application Server不僅提供連接池,而且還緩存你的PreparedStatements。
消除泄漏
有許多可用于幫助檢測和消除JDBC泄漏的過程和工具:
在開發過程中-盡早發現錯誤是迄今為止的最佳方法:
開發實踐:良好的開發實踐應在軟件離開開發人員之前減少軟件中的錯誤數量。具體做法包括:
1. 配對編程,以教育沒有足夠經驗的人
2. 代碼審查,因為許多眼睛勝過一只眼睛
3. 單元測試,這意味著你可以使用測試工具來練習所有代碼庫,從而使重現泄漏變得微不足道
4. 使用現有的庫進行連接池,而不是構建自己的庫
靜態代碼分析:使用出色的Findbugs之類的工具來執行靜態代碼分析。這會拾取許多未正確處理close()的地方。Findbugs有一個用于Eclipse的插件,但也可以一次性運行,并已集成到Jenkins CI和其他構建工具中
在運行時:
可保持性和提交
如果ResultSet的可保存性為ResultSet.CLOSE_CURSORS_OVER_COMMIT,則在調用Connection.commit()方法時關閉ResultSet。可以使用Connection.setHoldability()或使用重載的Connection.createStatement()方法進行設置。
2. 在運行時記錄。
在你的代碼中放置良好的日志語句。這些內容應該清晰易懂,以便客戶,支持人員和隊友無需培訓即可理解。它們應簡潔,并包括打印關鍵變量和屬性的狀態/內部值,以便你可以跟蹤處理邏輯。良好的日志記錄是調試應用程序(尤其是已部署的應用程序)的基礎。
你可以在項目中添加調試JDBC驅動程序(用于調試-請勿實際部署)。一個示例(我還沒有使用過)是log4jdbc。然后,你需要對此文件進行一些簡單的分析,以查看哪些執行沒有相應的關閉。計算打開和關閉應該突出顯示是否存在潛在問題
監視數據庫。使用諸如SQL Developer的“ Monitor SQL”功能或Quest的TOAD之類的工具監視正在運行的應用程序。本文介紹了監視。在監視期間,你查詢打開的游標(例如,從表v $ sesstat中)并查看其SQL。如果游標的數量在增加,并且(最重要的是)由一個相同的SQL語句控制,則你知道該SQL泄漏。搜索你的代碼并查看。
其他想法
你可以使用WeakReferences處理關閉的連接嗎?
弱引用和軟引用是允許你以允許JVM在其認為合適的任何時間對對象進行垃圾收集的方式來引用對象的方法(假定該對象沒有強大的引用鏈)。
如果將構造函數中的ReferenceQueue傳遞給軟引用或弱引用,則當對象發生GC對象時(如果根本發生),該對象將被放置在ReferenceQueue中。使用這種方法,你可以與對象的終結處理進行交互,并且可以在此時關閉或終結該對象。
幻像引用有些古怪;它們的目的僅是控制最終確定,但是你永遠無法獲得對原始對象的引用,因此很難在其上調用close()方法。
但是,嘗試控制何時運行GC并不是一個好主意(Weak,Soft和PhantomReferences 在對象已排隊進入GC 之后讓你知道)。實際上,如果JVM中的內存量很大(例如-Xmx2000m),則可能永遠不會對對象進行GC,并且仍然會遇到ORA-01000。如果JVM內存相對于程序要求而言較小,則可能會發現ResultSet和PreparedStatement對象在創建后立即被GC(在你可以從它們讀取之前),這很可能會使程序失敗。
TL; DR:弱引用機制不是管理和關閉Statement和ResultSet對象的好方法。
2020-03-01
總結
以上是生活随笔為你收集整理的java中sql去除游标_java.sql.SQLException:-ORA-01000:已超过最大打开游标的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 28岁戴牙套有用吗
- 下一篇: 隐形牙套每天要戴多少小时