語言:java,資料庫:oracle
開發中通過jdbc做批量删除對象時,出現了如下異常:
java.sql.SQLException: ORA-01000: 超出打開遊标的最大數
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:440)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:837)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:445)
出現這種異常的原因很明确:超出打開遊标的最大數。
分析:
Java代碼中,執行conn.createStatement()或conn.prepareStatement()建立statement時,相當于在資料庫中打開了一個cursor。是以,如果你的createStatement和prepareStatement是在一個循環裡面的話,就會非常容易出現這個問題,因為遊标在不停的打開卻沒有關閉。
解決這個問題的方法有兩種:
修改資料庫遊标cursor上限值

從上圖中可以看出oracle目前資料庫的遊标cursor上限值是300,我們需要修改它的值,如下圖所示将cursor值修改為最大值1000
從上圖可以看出oracle的遊标值已經被修改為1000了。
但是仔細思考就可以看出這種方法是治标不治本的,如果代碼的循環次數增多,依然會出現目前這個異常,是以最根本的解決方法是重構代碼。
重構java代碼
未重構前的代碼片段:
for (long i = 0; i <= 10000; i++) {
String sql = "insert into telepnum values(" + i + ")";
stmt = con.createStatement(); // 這裡是問題的所在
stmt.executeUpdate(sql);
}
重構後的代碼片段:
for (long i = 0; i <= 10000; i++) {
String sql = "insert into telepnum values(" + i + ")";
stmt = con.createStatement(); // 這裡是問題的所在
stmt.executeUpdate(sql);
stmt.close(); //及時關閉statement
}
更好的解決方案是将con.createStatement()語句放到循環的外面,一勞永逸。
con = insert.getConnection();
stmt = con.createStatement(); // 移動到這裡,Statemet是可以重用的
for (long c = a; c <= b; c++) {
String sql = "insert into telepnum values(" + c + ")";
stmt.executeUpdate(sql);
}
stmt.close(); //及時關閉statement
而且,絕大部分情況下,open_cursors隻需要設定一個比較小的值,就足夠使用了,除非有非常特别的要求。