有一个小程序, 处理数据库里的大量记录(百万条), 我用以下程序处理, 但是运行之后频繁出现内存溢出, 请教高人是怎么回事?程序框架:
//数据库连接使用连接池,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();
}
}
}
//数据库连接使用连接池,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();
}
}
}
~~~~~~~~~~~~~~这个我也试过了, 还是不能解决问题
在ORACLE中的实现是SELECT * FROM (SELECT A.NAME, ROWNUM RN FROM USER AS A) WHERE RN>=? AND ROWNUM <=?
有没有高手能帮忙?
java -Xms256M yourclass
回复人: eidolon_warrior(精灵_战士) ( ) 信誉:99 2006-02-08 09:30:00 得分: 0
数据量大可以分段处理
=======================================================我上边的程序就是分段处理的, 但是导致内存溢出,
我觉得可能是创建statement比较耗内存, 但是我即使用完立即关掉, 也没有解决问题,
你的程序里在pstq没有关闭的情况下又执行了pstd;并且你的freeconnection()到底合不合适?
建议你干脆有一个sql语句算了。
关于关掉statement, 我也曾试过用完立马就close(), 但是还是不行,
我总觉得是即时调用了close(), 也不是立即就能释放内存,我通过延时来等待, 但是也不行
========================================
分页处理
数据太多而又一次性完全输出是不明智的
========================================
我现在就是想分页处理阿, 但是分页处理就产生内存溢出(不是因为把所有内容都读取的缘故)
我现在就是想知道为什么分批处理也会溢出
不知为什么要这么做,一条delete语句不就搞定了吗?
另外,每次用完ResultSet没有close
楼主的代码好像是要删除所有满足条件的记录,每次外重循环删5000条
不知为什么要这么做,一条delete语句不就搞定了吗?
另外,每次用完ResultSet没有close
=====================================
因为我中间还要做一些其他操作,
所以不能直接全部delete我尝试过立即关掉ResultSet, 但是还是不行
楼主用的连接池是什么?
"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删除处理过的记录
有没有高手能帮忙?
还有就是如leadyu(大兵瑞恩)说,statement的执行次数受到JDBC实现的限制,最好不要放在循环块外,而应该放入外层while循环中;
外层循环完成前,先关闭rs,再关闭stmt;
删除不要在内层循环同do something放在一起执行,建议先用StringBuffer记住ID,然后在内层循环结束后,使用一条sql语句(= or 或者 in,id一定要有索引,否则百万条...)搞定删除;
其他方法,java还是要使用sql,就直接使用sql:创建临时表,然后insert into select...不说了,关键是不了解你的something是什么动作
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();
}
}
}
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();
}
}
}