ORA-01000: 超出打開遊標的最大數(解決及緣由)

仍是 chongqingdaxue 繳費平臺, 稅票打印完畢, 上傳到財務處時, 當稅票數目較少時(10幾張), 能正常上傳; 當數目較大時(408), 就上傳失敗. 查看 tomcat 日誌, 以下:html

clip_image001[4]

既然超出最大遊標數, 爲了第一間讓程序恢復正常運行, 固然"腳疼治腳", 先把最大遊標數調大:java

(1). DBA 登陸 PL/SQLsql

(2). 打開 Command Window(注意不是 SQL Window)數據庫

clip_image002[4]

(3). 輸入如下命令, 修改 oracle 最大遊標數爲 1000tomcat

SQL> alter system set open_cursors=1000 scope=both;

(4). 查看最大遊標數是否已修改爲功oracle

SQL> show parameter open_cursors;

(5). 重啓 tomcat(必定要有這一步, 不然修改不生效)函數

 

通過以上操做, 票據順利上傳上去了, 但是這樣治標不治本, 萬一之後來個1000張以上的票據要上傳, 那不就又得改遊標數了; 在代碼裏確定是每處理一張票就打開一個遊標的, 這樣是錯誤的. 網上找了這個錯誤代碼的相關說明, 在這裏發現如下這段話post

這樣的錯誤很容易出如今Java代碼中的主要緣由是:Java代碼在執行conn.createStatement()和 conn.prepareStatement()的時候,實際上都是至關與在數據庫中打開了一個cursor。尤爲是,若是你的 createStatement和prepareStatement是在一個循環裏面的話,就會很是容易出現這個問題。由於遊標一直在不停的打開,並且沒有關閉。


在代碼裏看了一下, 果真是這樣, 程序經過循環調用封裝好的 executeSql 函數, 來對每張票進行 update, 而 executeSql 裏每次都調用了 conn.prepareStatement(); 將其移出循環, 再改回原遊標數, 再上傳票據, 就再也不報錯了.大數據

public static void executeSql(Connection conn, String sql, Object[] parValue) throws Exception{
	PreparedStatement ps = null;
	try {
		LOGGER.info(sql);
		ps = conn.prepareStatement(sql);
		if (parValue != null){
			String params = "";
			for (int i = 0; i < parValue.length; i++){
				if (i != 0){
					params += ",";
				}
				ps.setObject(i+1, parValue[i]);
				params += parValue[i];
			}
			LOGGER.info(params);
		}
		ps.execute();
	} catch (SQLException e) {
		e.printStackTrace();
		throw new Exception();
	} finally {
		if (ps != null){
			ps.close();
		}
	}
}

注: 原代碼有進行 ps.close(); , 可是仍然無效, 是由於 connection 的 autocommit 設爲 false 的緣由? 仍是由於 connection 是從鏈接池取的緣由呢? spa

這裏有一個問題說明 connection 與 prepareStatement 進行 close 的關係, 但這裏只是說明了直接 close connection, 而沒有說明直接 close prepareStatement.

問:

用CONNECTION 建立了 PREPAREDSTATEMENT ,用完了 PREPAREDSTATEMENT 後,沒有關閉PREPAREDSTATEMENT ,而是直接 CLOSE CONNECTION ,這麼作有什麼隱患嗎?

答:

若是沒有使用數據庫鏈接池,而是每次建立物理鏈接,而後釋放的話,沒有什麼問題。close Connection的時候已經把數據庫資源徹底釋放掉了,PreparedStatement佔用的數據庫遊標也會隨即釋放。 可是大部分狀況讀寫數據庫都會採用數據庫鏈接池來提升鏈接效率,在這種狀況下有潛在的隱患。 由於數據庫鏈接池中拿到一個Connection,close的時候不是真正關閉鏈接,釋放數據庫資源,而是把鏈接歸還給鏈接池。所以在這種狀況下,close了Connection,可是PreparedStatement並無被釋放掉,佔用的數據庫遊標仍然處於打開狀態。所以在大數據訪問量的狀況下很容易出現數據庫遊標使用到最大,沒法分配遊標錯誤。


 環境: Oracle 10g

相關文章
相關標籤/搜索