有一个小程序, 处理数据库里的大量记录(百万条), 我用以下程序处理, 但是运行之后频繁出现内存溢出, 请教高人是怎么回事?程序框架:
//数据库连接使用连接池,mysql数据库
private void myfunc(){
  Connection conn = getConnection();
  String sql_q = "select id, vol_1, vol_2 from tablename where conditions limit 5000";//
  String sql_d = "delete from tablename where id=?";
  boolean flag = true;
  try{
     PrepareStatement pstq = conn.prepareStatement(sql_q);
     PrepareStatement pstd = conn.prepareStatement(sql_d);
     while(flag){
        ResultSet rs = pstq.executeQuery();
        if(!rs.next()){
           flag = false;
           break;
        }else{
           rs.beforefirst();
           while(rs.next()){
                // do something
                pstd.setint(1, rs.getInt("id"));
                pstd.executeUpdate();
           }
        }
     }catch(SQLException ex){
         //do something;
     }finally{
         freeConnection();
     }
  }
}

解决方案 »

  1.   

    主要就是想循环的处理这批数据,我觉得创建statement会耗内存, 但是怎么避免呢?
      

  2.   

    用完就 close
    ~~~~~~~~~~~~~~这个我也试过了, 还是不能解决问题
      

  3.   

    感觉是while循环里面创建的ResultSet没有释放的问题。
      

  4.   

    用分也读取
    在ORACLE中的实现是SELECT * FROM (SELECT A.NAME, ROWNUM RN FROM USER AS A) WHERE RN>=? AND ROWNUM <=?
      

  5.   

    你写一句sql语句来完成不行吗?
      

  6.   

    分页读取, 在mysql上一般用Limit读取一定的行数select * from table where conditions limit offset, number;其中offset = offset + number;我上边的程序也是用这个方法的, 但是经常内存溢出, 
    有没有高手能帮忙?
      

  7.   

    调用java时加上参数:
    java -Xms256M yourclass
      

  8.   

    ====================================================== 
    回复人: eidolon_warrior(精灵_战士) ( ) 信誉:99  2006-02-08 09:30:00  得分: 0  
     
     
       数据量大可以分段处理
    =======================================================我上边的程序就是分段处理的, 但是导致内存溢出,
    我觉得可能是创建statement比较耗内存, 但是我即使用完立即关掉, 也没有解决问题,  
     
      

  9.   

    我用oracle数据库(数据量也很大)时也曾遇到过内存溢出的问题,最后查找原因还是statement的问题,打开的太多,没有及时关闭。
    你的程序里在pstq没有关闭的情况下又执行了pstd;并且你的freeconnection()到底合不合适?
    建议你干脆有一个sql语句算了。
      

  10.   

    我用的是 连接池, freeDbConnect()是连接池的一个方法, 
    关于关掉statement, 我也曾试过用完立马就close(), 但是还是不行, 
    我总觉得是即时调用了close(), 也不是立即就能释放内存,我通过延时来等待, 但是也不行
      

  11.   

    你的 statement 和 resultset 我感觉都没有关!!
      

  12.   

    PrepareStatment重复使用的问题,建议使用批处理或两条语句整合为一条语句。
      

  13.   

    to  tianshul8(闲耘):
    ========================================
    分页处理
    数据太多而又一次性完全输出是不明智的
    ========================================
    我现在就是想分页处理阿, 但是分页处理就产生内存溢出(不是因为把所有内容都读取的缘故)
    我现在就是想知道为什么分批处理也会溢出
      

  14.   

    是不是虽然你的statement 关掉了。但是由于连接池的问题导致一部分资源没有释放。用内存监测工具看看到底是什么资源没有被释放。还有什么资源再不断增加就知道了
      

  15.   

    PrepareStatement 没关,连接池一般有两种设置,一种是关了CONN自动关所有PrepareStatement ,一种是不关,缓存起来
      

  16.   

    楼主的代码好像是要删除所有满足条件的记录,每次外重循环删5000条
    不知为什么要这么做,一条delete语句不就搞定了吗?
    另外,每次用完ResultSet没有close
      

  17.   

    =====================================
    楼主的代码好像是要删除所有满足条件的记录,每次外重循环删5000条
    不知为什么要这么做,一条delete语句不就搞定了吗?
    另外,每次用完ResultSet没有close
    =====================================
    因为我中间还要做一些其他操作,
    所以不能直接全部delete我尝试过立即关掉ResultSet, 但是还是不行
      

  18.   

    很多连接池关Statement 的时候会自动关掉该Statement 的所有ResultSet,所以ResultSet不关也没什么,但是PrepareStatement最好要关,CONN有限制一个连接最多开多少Statement,并且CONN关的时候不见得会关Statement。
       楼主用的连接池是什么?
      

  19.   

    还有一点,MYSQL的Statement好象不断的重新SET参数执行500次左右就不行了,以前我遇到过,需要重新生成一个Statement 。
      

  20.   

    不过我总觉得你这样一条条删实在效率太我知道你先SELECT出来要做处理后才能删,但也不需要一条条删除。其实我的理解,你应该是担心
    "select id, vol_1, vol_2 from tablename where conditions limit 5000";//和
    "delete from tablename where conditions limit 5000";//各同样conditions得到的结果集不同而删错,是吗?其实有不少解决办法,我说两种,看看对你有没帮助。第一方法,假设主键是永远递增的,
    那么,可以这样写
    "select id, vol_1, vol_2,max(id) as end,min(id) as begin from tablename where conditions limit 5000";//
    一条条处理完后,
    "delete from tablename where conditions and id>=begin and id<=end,因为你的主键永远递增所以不用担心SELECT处理的同时插进来的数据第二方法:
    如果你的表不会同时很多连接写入,其实可以SEELCT的同时锁住表,然后在用同样条件where conditions删除处理过的记录
      

  21.   

    分页读取, 在mysql上一般用Limit读取一定的行数select * from table where conditions limit offset, number;其中offset = offset + number;我上边的程序也是用这个方法的, 但是经常内存溢出, 
    有没有高手能帮忙?
      

  22.   

    建议每次循环前后,报告一下JVM内存使用情况,看一下是JVM Xmx设置太小,还是循环后资源没有释放,同时也要监视sql语句的执行快慢和数据库的性能。
    还有就是如leadyu(大兵瑞恩)说,statement的执行次数受到JDBC实现的限制,最好不要放在循环块外,而应该放入外层while循环中;
    外层循环完成前,先关闭rs,再关闭stmt;
    删除不要在内层循环同do something放在一起执行,建议先用StringBuffer记住ID,然后在内层循环结束后,使用一条sql语句(= or 或者 in,id一定要有索引,否则百万条...)搞定删除;
    其他方法,java还是要使用sql,就直接使用sql:创建临时表,然后insert into select...不说了,关键是不了解你的something是什么动作
      

  23.   

    private void myfunc(){
      Connection conn1 = getConnection();
      Connection conn2 = getConnection();
      String sql_q = "select id, vol_1, vol_2 from tablename where conditions limit 5000";//
      String sql_d = "delete from tablename where id=?";
      boolean flag = true;
      try{
         PrepareStatement pstq = conn1.prepareStatement(sql_q);
         PrepareStatement pstd = conn2.prepareStatement(sql_d);
         while(flag){
            ResultSet rs = pstq.executeQuery();
            if(!rs.next()){
               flag = false;
               break;
            }else{
               rs.beforefirst();
               while(rs.next()){
                    // do something
                    pstd.setint(1, rs.getInt("id"));
                    pstd.executeUpdate();
               }
            }
    if (rs != null){
    rs.close();
    }
         }catch(SQLException ex){
             //do something;
         }finally{
             freeConnection();
         }
      }
    }
      

  24.   

    PrepareStatement 和 ResultSet 用完后都应该及时关闭。
      

  25.   

    你看一下这样改行不:
    private void myfunc(){
    Connection conn = null;
    PrepareStatement pstq = null;
    PrepareStatement pstd = null;
    ResultSet rs = null;
    conn = getConnection();
    String sql_q = "select id, vol_1, vol_2 from tablename where conditions limit 5000";//
    String sql_d = "delete from tablename where id=?";
    boolean flag = true;
    try{
    pstq = conn.prepareStatement(sql_q);
    pstd = conn.prepareStatement(sql_d);
    while(flag){
    rs = pstq.executeQuery();
    if(!rs.next()){
    flag = false;
    break;
    }else{
    rs.beforefirst();
    while(rs.next()){
    // do something
    pstd.setint(1, rs.getInt("id"));
    pstd.executeUpdate();
    }
    rs.close();
    rs = null;
    }
    }catch(SQLException ex){
    //do something;
    }finally{
    freeConnection();
    if(rs!=null) rs.close();
    if(pstq!=null) pstq.close();
    if(pstd!=null) pstd.close();
    }
    }
    }