仍是 chongqingdaxue 繳費平臺, 稅票打印完畢, 上傳到財務處時, 當稅票數目較少時(10幾張), 能正常上傳; 當數目較大時(共408張), 就上傳失敗. 查看 tomcat 日誌, 以下:html
既然超出最大遊標數, 爲了第一間讓程序恢復正常運行, 固然"腳疼治腳", 先把最大遊標數調大:java
(1). 以 DBA 登陸 PL/SQLsql
(2). 打開 Command Window(注意不是 SQL Window)數據庫
(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