Collus

惜秦怀古

BlogJava 首页 新随笔 联系 聚合 管理
  0 Posts :: 6 Stories :: 0 Comments :: 0 Trackbacks
Java开发中,使用Oracle数据库的时候,经常会碰到有ORA-01000: maximum open cursors exceeded.的错误。 

实际上,这个错误的原因,主要还是代码问题引起的。 
ORA-01000: maximum open cursors exceeded,表示已经达到一个进程打开的最大游标数。

   这样的错误很容易出现在Java代码中的主要原因是:Java代码在执 行conn.createStatement()和conn.prepareStatement()的时候,实际上都是相当与在数据库中打开了一个 cursor。尤其是,如果你的createStatement和prepareStatement是在一个循环里面的话,就会非常容易出现这个问题。因 为游标一直在不停的打开,而且没有关闭。

一般来说,在写Java代码的时候,createStatement和prepareStatement都应该要放在循环外面,而且使用了这些 Statment后,及时关闭。最好是在执行了一次executeQuery、executeUpdate等之后,如果不需要使用结果集 (ResultSet)的数据,就马上将Statment关闭。 

对于出现ORA-01000错误这种情况,单纯的加大open_cursors并不是好办法,那只是治标不治本。实际上,代码中的隐患并没有解除。 
而且,绝大部分情况下,open_cursors只需要设置一个比较小的值,就足够使用了,除非有非常特别的要求。

oracle 9i 默认的open_cursors=300  


一、看有问题的代码

 1 import java.sql.Connection;
 2 import java.sql.DriverManager;
 3 import java.sql.SQLException;
 4 import java.sql.Statement;
 5 
 6 public class Test {
 7   public Connection getConnection() {
 8     String url = "jdbc:oracle:thin:@localhost:1521:ora9i";
 9     String user = "scott";
10     String password = "tiger";
11     Connection con = null;
12     try {
13       Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
14       con = DriverManager.getConnection(url, user, password);
15     } catch (Exception e) {
16       e.printStackTrace();
17     }
18     return con;
19   }
20 
21   public static void main(String[] args) throws SQLException {
22     long a = 13819100000L;
23     long b = 13819100600L// 问题点
24     Connection con = null;
25     Statement stmt = null;
26     Test insert = new Test();
27     try {
28       con = insert.getConnection();
29       for (long c = a; c <= b; c++) {
30         String sql = "insert into telepnum values(" + c + ")";
31         stmt = con.createStatement(); // 这里是问题的所在
32         stmt.executeUpdate(sql);
33       }
34       System.out.println("OK");
35     } catch (Exception e) {
36       e.printStackTrace();
37     } finally {
38       if (con != null) {
39         con.close();
40       }
41     }
42   }
43 }

二、分析

在循环里面每次都 stmt = con.createStatement(); 而没有释放,这样每个都占用了一个服务器的游标资源,最后造成失败

三、解决方案

1、增加关闭语句
 
1   con = insert.getConnection();
2       for (long c = a; c <= b; c++) {
3         String sql = "insert into telepnum values(" + c + ")";
4         stmt = con.createStatement(); // 这里是问题的所在
5         stmt.executeUpdate(sql);
6         stmt.close(); // 用完了就关闭好了
7       }

2、将这句话移动到循环外面,推荐用这个
1 con = insert.getConnection();
2       stmt = con.createStatement(); // 移动到这里,Statemet是可以重用的
3       for (long c = a; c <= b; c++) {
4         String sql = "insert into telepnum values(" + c + ")";
5         stmt.executeUpdate(sql);
6       }
7       stmt.close(); // 用完了就关闭好了

3、改装成批量更新
1 con = insert.getConnection();
2       con.setAutoCommit(false);
3       stmt = con.createStatement(); // 移动到这里,Statemet是可以重用的
4       for (long c = a; c <= b; c++) {
5         String sql = "insert into telepnum values(" + c + ")";
6         stmt.addBatch(sql);
7       }
8       stmt.executeBatch();
9       con.commit();


四、总结

    鉴于上面的问题,在做基类的时候,在对数据进行DML操作的时候,尽量不要让基类返回Statement,而应该在基类直接进行关闭。在做查询的时候,可 以把statement留给程序员自己进行手动关闭,关闭的方法为:给ResultSet一个方法可以得到Statement,然后再关闭 Statement。个人认为这种方法是比较妥当的。
posted on 2010-04-16 20:37 良帅 阅读(2378) 评论(0)  编辑  收藏 所属分类: ORACLE

只有注册用户登录后才能发表评论。


网站导航: