最近在做的一个程序,遇到了一个JDBC方面的问题,我的代码如下
 public  ResultSet  executeSql(String sqlstr)
  {
     Statement stmt = null;
     ResultSet  rs = null;      try
     {
       stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
       rs=stmt.executeQuery(sqlstr);
       DebugLog.logger.log(Level.INFO,"获取数据集成功");
       return rs;
     }
     catch(SQLException e)
     {
       DebugLog.logger.log(Level.WARNING,"获取数据集时出现错误");
       DebugLog.logger.log(Level.WARNING,e.getMessage());
       try{
        conn.rollback();
       }
       catch(SQLException i)
   {
        DebugLog.logger.log(Level.WARNING,"回滚数据集时出现错误");
        DebugLog.logger.log(Level.WARNING,i.getMessage());
   }
       return null;
     }
     catch(Exception cnfe){
      DebugLog.logger.log(Level.WARNING,"获取数据集时出现错误");
     DebugLog.logger.log(Level.WARNING,cnfe.getMessage());
     return null;
     }   }
这是我之前写的一段JDBC操作数据库的代码,但是主程序运行一段时间出现这样的异常ora-01000: maximum open cursors exceeded.到网上查了下,说是已经达到一个进程打开的最大游标数,Java代码在执行conn.createStatement()和conn.prepareStatement()的时候,实际上都是相当与在数据库中打开了一个cursor。
尤其是,如果你的createStatement和prepareStatement是在一个循环里面的话,就会非常容易出现这个问题。因为游标一直在不停的打开,而且没有关闭,所以说,最好在执行了一次executeQuery、executeUpdate等之后,如果不需要使用结果集(ResultSet)的数据,就马上将Statment关闭。然后我的代码改进如下
 public  ResultSet  executeSql(String sqlstr)
  {
     Statement stmt = null;
     ResultSet  rs = null;      try
     {
       stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
       rs=stmt.executeQuery(sqlstr);
       DebugLog.logger.log(Level.INFO,"获取数据集成功");
       return rs;
     }
     catch(SQLException e)
     {
       DebugLog.logger.log(Level.WARNING,"获取数据集时出现错误");
       DebugLog.logger.log(Level.WARNING,e.getMessage());
       try{
        conn.rollback();
       }
       catch(SQLException i)
   {
        DebugLog.logger.log(Level.WARNING,"回滚数据集时出现错误");
        DebugLog.logger.log(Level.WARNING,i.getMessage());
   }
       return null;
     }
     catch(Exception cnfe){
      DebugLog.logger.log(Level.WARNING,"获取数据集时出现错误");
     DebugLog.logger.log(Level.WARNING,cnfe.getMessage());
     return null;
     }finally{
      try{
      if(rs != null){
      rs.close();
      }
      if(stmt != null){
      stmt.close();
      }
      }catch(SQLException j){
      DebugLog.logger.log(Level.WARNING,"关闭数据集时出现错误");
     DebugLog.logger.log(Level.WARNING,j.getMessage());
      }       
     }
  }
但是这段代码的问题是,每次取这段代码执行SQL后返回的记录集,就会抛出一个信息为null的异常,我猜想是上面这个函数没返回任何记录集,rs是null的?
实在不知道什么原因,求高人指教,是什么原因?应该如何修改?谢谢了,我分不多,实在抱歉

解决方案 »

  1.   

    java里面返回的ResultSet如果关闭连接,ResultSet就会变成null了
      

  2.   

    那问下,这个问题要如何解决呢?有没有简单一点的方法,rs不关闭又会出现ora-01000: maximum open cursors exceeded这种异常哈
      

  3.   

    这样的用法有问题。
    首先,在一个方法里面解决ResultSet的获取和关闭不是一个好选择,除非你使用其他东西(比如自己编写容器)缓存数据。因为关闭ResultSet导致结果集不能访问,关闭Statement也是一样。
    其次,你的游标数越界,仅仅是因为你没有关闭Statement,而不是你没有“在这个方法里”关闭它。你完全可以在提取完ResultSet的数据后再关闭它。
    第三,在你的第二个代码片段里,没有看到可以让返回值是null的地方,除了那个return null。不要受楼上lingkeylbh(凌可)的误导,java可没有那个本事。
      

  4.   

    多谢weihthchk(Spectrum)兄弟
    恩,我试试在这个方法外面关闭它吧,不过因为每次打开都需要相应的关闭,所以我才那样写,不会遗漏关闭的问题
    第三:我的说的出现信息为null的异常,倒不是这个函数的返回值是null,我的main 函数
    public static void main(String[] args) {
    // TODO Auto-generated method stub
    ResultSet  rs1;
    int count = 0;
    ConnDatabase sql1 = new ConnDatabase();
    // sql1.ConnOracle();
    sql1.ConnSqlServer();
    //     String sql;
        sql1.ConnectThreeTimes();
        
        
    //     sql = "insert into tbl_eleccsss_v(Instruct_id,Srv_code,Id,Succ_flag,Err_msg,";
    //     sql+="Name,Descrb,Addr,Principal,Phone,Eye_count,Re,server_id,acc_id,cust_id)";
    //     sql+=" values(200062702,'000e',3,1,'error','dsf','fsddf','fsdf','fdf','50855657',32,'fds',324,'dsa',2556)";
        //rs1=sql1.executeSql("select au_id,au_lname from authors");
    //     sql1.executeUpdate(sql);
        rs1=sql1.executeSql("SELECT * FROM CSSSTOTELSMS");
        //rs1=sql1.executeSql(sql);
        try
        {
          while(rs1.next())
          {
            System.out.println(" ID: "+rs1.getString("ID"));       }
        }
       
        catch(SQLException sqlex2)      {          System.out.println(          ".mymethod - 不能关闭数据库连接: " +          sqlex2.toString());      }
     catch(Exception e)
        {
           System.out.println(e.getMessage());
        }    } 
    在这个主函数里,抛出了null的异常
      

  5.   

    如果你使用了连接池,就不会担心关闭和打开的开销了
    连接池的connection的关闭只是将连接实例返回到连接池中
    但是statment和resultset一定压迫关闭
    因为这个和数据库连接的开销有关
    如果你需要相关的数据,可以通过建立一个List
    将需要的值拷贝到里面 然后关闭statment和resultset 返回呵呵 不过Hibernate有更好的解决方案忙 就说到这里了
      

  6.   

    to davidzgz(老哥们):Hibernate是不是只能在web程序里使用啊?但是我现在做的不是web程序哈,是在UNIX上后台运行的一个进程,现在做的项目是电信的一个新业务,这个进程需要在后台不停的处理数据,本来想用C来写的,因为我们公司之前的都是用C来实现,但是不知道怎么用C连接SQLSERVER,之前公司的都是连的oracle,所以改用java了,而且java操作数据库也比c简单的多,这个程序对性能也没太高的要求
      

  7.   

    你既然要把rs作为结果return回去,就不能关闭rs及相关的stmt和conn,解决办法就是不能返回ResultSet,而要把ResultSet例面的数据取出来放在List里面返回去,这样就不会有错了
      

  8.   

    还有,我试过weihthchk(Spectrum)的方法了,在取完数据后在关闭statment和resultset,但是因为我的程序的数据库操作太频繁(这个进程要处理一个省的用户的数据,想想数据量还是很大的,所以对数据库操作比较多),所以在每次操作完在关闭,显的很麻烦,而且有的时候还不好关闭,比如
                     rs3 = this.Conn1.executeSql(sql3);
    try{
    while(rs3.next()){
    ........
    rs4 = this.Conn1.executeSql(sql4);

    try{
    while(rs4.next()){

    .........
      }catch(){
      
      }
     }
     }catch(){ 
      
     }
    上面这段怎么关闭statment和resultset?其中this.Conn1是和一个数据库的连接,对这个数据库嵌套做了操作,如果里层的while(rs4.next())关闭了statment和resultset,会不会影响外层的while(rs3.next())而使外层的循环不能在继续了难道要解决这个问题只能改用连接池技术了,我到现在还没用过连接池呢,而且现在这个新业务除了现在这个问题外,就是运行时间长了会出现ora-01000: maximum open cursors exceeded.,业务处理上已经测试没什么问题了,改用连接池的话整个程序得大改了吧,不是还得重新测试?各位有没有更好的解决方法啊
      

  9.   

    谢谢li_d_s(鄙视那些不懂Java却跑来乱骂的人,.NET没啥了不起),我试下你的方法哈,呵呵,好象在一个灌水在帖子里看到过你
      

  10.   

    还有,我的这个程序里connection是不用关闭的,因为要不停的操作数据库,所以连接一直保持,只是statment和resultset操作完之后需要关闭,因为我的数据库操作是放在一个无限循环里的,操作完数据不关闭会出问题的