或者错误:ORA-01000: maximum open cursors exceeded
以上两种错误就表名oracle游标超出了最大值,客户端把连接oracle的光标用光了。
定位问题:Resultset,循环执行rs.next(),假如我的记录数很多,连接一致不断开,就会用光游标
这样的错误很容易出现在Java代码中的主要原因是:Java代码在执行conn.createStatement()和 conn.prepareStatement()的时候,实际上都是相当与在数据库中打开了一个cursor。
尤其是,如果你的 createStatement和prepareStatement是在一个循环里面的话,就会非常容易出现这个问题。因为游标一直在不停的打开,而且没有关闭。
我测试了一下,我的oracle游标默认是300,大概用rs.next()这种方式取5000条数据就会报错了。
解决方案:
(1). 以 DBA 登录 PL/SQL
(2). 查看最大游标数是否已修改成功
SQL> show parameter open_cursors;
一般游标数为几百个,我的是300.
(3). 我们可以通过增大游标数,来解决此问题。
SQL> alter system set open_cursors=1000 scope=both;
(4). 查看最大游标数是否已修改成功
SQL> show parameter open_cursors;
问:
用CONNECTION 创建了 PREPAREDSTATEMENT ,用完了 PREPAREDSTATEMENT 后,没有关闭PREPAREDSTATEMENT ,而是直接 CLOSE CONNECTION ,这么做有什么隐患吗?
答:
如果没有使用数据库连接池,而是每次创建物理连接,然后释放的话,没有什么问题。close Connection的时候已经把数据库资源完全释放掉了,PreparedStatement占用的数据库游标也会随即释放。 但是大部分情况读写数据库都会采用数据库连接池来提高连接效率,在这种情况下有潜在的隐患。 因为数据库连接池中拿到一个Connection,close的时候不是真正关闭连接,释放数据库资源,而是把连接归还给连接池。因此在这种情况下,close了Connection,但是PreparedStatement并没有被释放掉,占用的数据库游标仍然处于打开状态。因此在大数据访问量的情况下很容易出现数据库游标使用到最大,无法分配游标错误。
如果你要用到Connection取记录,并且记录可能很多的话,请不要用druid连接池,请用传统jdbc方法,并且在每次循环结束后关闭Conn,这样就不会出现这个问题了。
/** * 获取JDBC连接 * * @param url * @param username * @param password * @return */ private Connection getConnection(String url, String username, String password) { Connection conn = null; try { // 不需要加载Driver. Servlet 2.4规范开始容器会自动载入 // conn = DriverManager.getConnection(url, username, password); // Properties info = new Properties(); // info.put("user", username); info.put("password", password); conn = DriverManager.getConnection(url, info); } catch (SQLException e) { e.printStackTrace(); } return conn; }