语言: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只需要设置一个比较小的值,就足够使用了,除非有非常特别的要求。