先来看我的线程
private DataHandle dh = new DataHandle();public synchronized void runTask() {
try {
dh.handle(pbean.getStartNo(), pbean.getEndNo()); } catch (Exception e) {
e.printStackTrace();
// TaskManagerBean.returnItem();
}这个是我的线程,里面用到一个叫DataHandle的类,现在来看这个DataHandle的类public synchronized void handle(String start, String end) { Statement stmt = null;
ResultSet rs = null;
StringBuffer sb = new StringBuffer();

try {
if (conn != null) { sb.append("select tid,tname,description,dbvalue,xmlvalue");
sb.append(" from exporttable limit " + start + "," + end);
System.out.println("sql===" + sb.toString());
stmt = conn.createStatement();

rs = stmt.executeQuery(sb.toString());
while (rs.next()) {
db = new DataBean();
db.setTname(StringUtil.replaceNull(rs
.getString("tname")));
db.setDescription(StringUtil.replaceNull(rs
.getString("description")));
db.setDbValue(StringUtil.replaceNull(rs
.getString("dbvalue")));
db.setXmlValue(StringUtil.replaceNull(rs
.getString("xmlvalue")));
/* resultList.add(db); */
// dealing(db);
}
/* return resultList; */ }
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
rs.close();
                                rs = null;
} catch (Exception e) {
}

try {
stmt.close();
                                stmt = null; } catch (Exception e) {
}
try {
conn.close();
                                conn = null;
} catch (Exception e) {
}

}
}这个类里有一个handle方法这个线程是这样运行的,5个线程第一个线程取0-100条记录
第二个线程取100-200条记录
第三个线程取200-300条记录
.
.
.
依此类推,现在的问题时,程序在运行时经常出现:resultset have been closed这样的问题经分析,是因为5个线程中,每个线程都有操作DataHandle的类,那么内存中就有5个DataHandle类,每个类中由于都进行resultset的打开,因此在运行时,
会发生一个线程中的ResultSet还在被操作时,已经被另一个线程中的ResultSet关闭的情况我试过了
在DataHandle中Synchronized(rs),synchronized(stmt),甚至我的方法大家都看到了,都是synchronized的,为什么还会发生这样的事,大家有没有好的解决方法多说一句,每个DataHandle中打开一个connection,然后操作完100条数据后关闭,因此始终是存在5个线程,5个connection,5个resultset.还是我的设计上有问题,我的设计就想是
多个线程,同时读数据库,只不过是每个线程读不同的数据块,就像我前面提到过的一样,0-100,100-200这样读的.

解决方案 »

  1.   

    你的conn不是每个方法里面一个.是用的成员~ 从你方法中没有conn
    的声明就可以看出来.而你在每次方法执行的最后有
    try { 
    conn.close(); 
                                    conn = null; 
    } catch (Exception e) { 
    } connection已经关闭.也就是说resultset也关闭了.是肯定会抛异常的.
      

  2.   

    我每个线程里自己造一个Connection的,我没有把这个Connection方法贴出来而己,不是5个线程公用一个connection,每个线程中都含有connection的新建和打开.我已经说了,5个线程,造了5个Connection,因为我始终控制好只打开5个CONNECTION,这点我也通过数据库或容器的MONITOR窗口看到了
      

  3.   

    package org.sky.threadgroup.db;import org.sky.util.*;
    import java.sql.*;
    import java.util.*;
    import org.sky.threadgroup.BeanUtil.*;public class DataHandle { private synchronized Connection getConnection() {
    Connection conn = null;
    try {
    DataConnection dataConn = new DataConnection();
    conn = dataConn.getDataConnection();
    return conn;
    } catch (Exception e) {
    e.printStackTrace();
    return null;
    }
    }
    public void handle(String start, String end) { Statement stmt = null;
    ResultSet rs = null;
    StringBuffer sb = new StringBuffer();
    /* ArrayList resultList = new ArrayList(); */
    DataBean db = null;
    Connection conn = null;
    try {
    conn = getConnection();
    if (conn != null) { sb.append("select tid,tname,description,dbvalue,xmlvalue");
    sb.append(" from exporttable limit " + start + "," + end);
    System.out.println("sql===" + sb.toString());
    stmt = conn.createStatement(); rs = stmt.executeQuery(sb.toString());
    while (rs.next()) {
    db = new DataBean();
    db.setTname(StringUtil.replaceNull(rs.getString("tname")));
    db.setDescription(StringUtil.replaceNull(rs
    .getString("description")));
    db.setDbValue(StringUtil.replaceNull(rs
    .getString("dbvalue")));
    db.setXmlValue(StringUtil.replaceNull(rs
    .getString("xmlvalue"))); }
    } } catch (Exception e) {
    e.printStackTrace();
    System.out.println(db.getTname() + ":" + db.getDescription() + ":"
    + db.getDbValue() + ":" + db.getXmlValue());
    /* return null; */
    } finally {
    synchronized (conn) {
    try {
    if (rs != null) {
    rs.close();
    rs = null;
    }
    } catch (Exception e) {
    }
    try {
    if (stmt != null) {
    stmt.close();
    stmt = null;
    }
    } catch (Exception e) {
    }
    try {
    if (conn != null) {
    conn.close();
    conn = null;
    }
    } catch (Exception e) {
    }
    }
    } }}
      

  4.   

    哪位大侠能指点迷津啊,痛苦啊!
    一会报这个java.sql.SQLException: The result set is closed.一会报这个
    java.sql.SQLException: operation not allowed before rs
      

  5.   

    到处都是synchronized 你这多线程几乎提升不了什么速度,比串行快不了哪去
    每个线程使用一个conntion即可,在业务上需要同步的地方同步一点点即可。
      

  6.   


    你就没看完我的贴,我是在每个线程里用到一个CONNECTION了,怎么没看清就发贴呀!
      

  7.   

    我的CONNECTION是这样得到的,在JBOSS里建了一个数据库连接池,然后try{
    Properties props = new Properties();
    props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
    props.setProperty("java.naming.provider.url", "localhost:9099");
    Context ctx = new InitialContext(props);
    ds = (DataSource) ctx.lookup("MySqlDS");
    }catch(Exception e){
    ds = null;
    e.printStackTrace();
    }客户端得到CONNECTION是通过ds.getConnection()这样得到的,是不是由于得到的connection不是ThreadLocal的关系?
      

  8.   

    5个线程,5个数据库连接,是不会产生楼主所说的问题的。
    而且,也没有必要使用synchronized关键字,
    因为,按照楼主的思路,应该是每个线程都负责数据处理的整个过程,
    只不过,数据来源被拆分了,而已。我想 , 问题的关键,应该是5个线程使用了同一个连接,使得所产生的rs有关联,关闭一个,其他的就不能够使用。
      

  9.   

    一般这种数据处理的问题,其瓶颈应该不是在查询速度上,
    所以,我给楼主一个参考方案。内容如下:
    1.创建DataBean,对应查询数据的每一条记录。
    2.创建一个固定大小的线程安全的阻塞队列,用于存放查询的数据。
    3.使用一个线程,对数据库进行查询,将查询数据放入队列。
      (这个查询,可以使用如下方式,多次查询,每次只查一部分,各部分数据不重复)
    4.创建4~5个线程,用于对查询数据的处理。
      (从队列里面取出数据,进行处理即可)
      

  10.   


    原来一个EOD要8小时,经我们这样一改进成了40分钟,你说效率有没有提高?关键在于设计,在于编码,更离谱的是我听到过某些人说RS。NEXT这样的操作就不能做并行,我晕,真不想多说你们这样的人!
      

  11.   

    原来一个EOD要8小时,经我们这样一改进成了40分钟,你说效率有没有提高?关键在于设计,在于编码,更离谱的是我听到过某些人说RS。NEXT这样的操作就不能做并行,我晕,真不想多说你们这样的人!
      

  12.   

    我并不觉得自己菜,给你回帖也只是想帮你一下,
    CSDN只是提供了一个交流的平台,
    如果楼主觉得你的水平远高于我们,下次有问题可以不要到这里提。
      

  13.   

    CSDN的人是很菜,但是写同样的功能,肯定不用40分钟,谢谢,代码,需求,系统都在你手里面,不再我们手里面,如果你们的系统很行,也不会来这提问解决了。40分钟很快吗?我也不想多说什么,我是比较菜的csdn人。