多线程中操作数据库,resultset被另一个线程提前关闭而出错,救大侠们的解答

TGITCIC
Java领域优质创作者
博客专家认证
2008-10-19 04:56:32
先来看我的线程


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这样读的.
...全文
562 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
sunyujia 2008-10-20
  • 打赏
  • 举报
回复
CSDN的人是很菜,但是写同样的功能,肯定不用40分钟,谢谢,代码,需求,系统都在你手里面,不再我们手里面,如果你们的系统很行,也不会来这提问解决了。40分钟很快吗?我也不想多说什么,我是比较菜的csdn人。
冰思雨 2008-10-20
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 lifetragedy 的回复:]

CSDN上的人好菜!
[/Quote]
我并不觉得自己菜,给你回帖也只是想帮你一下,
CSDN只是提供了一个交流的平台,
如果楼主觉得你的水平远高于我们,下次有问题可以不要到这里提。
TGITCIC 2008-10-20
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 sunyujia 的回复:]
到处都是synchronized 你这多线程几乎提升不了什么速度,比串行快不了哪去
每个线程使用一个conntion即可,在业务上需要同步的地方同步一点点即可。
[/Quote]
原来一个EOD要8小时,经我们这样一改进成了40分钟,你说效率有没有提高?

关键在于设计,在于编码,更离谱的是我听到过某些人说RS。NEXT这样的操作就不能做并行,我晕,真不想多说你们这样的人!
TGITCIC 2008-10-20
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 lifetragedy 的回复:]
自己顶
[/Quote]

原来一个EOD要8小时,经我们这样一改进成了40分钟,你说效率有没有提高?

关键在于设计,在于编码,更离谱的是我听到过某些人说RS。NEXT这样的操作就不能做并行,我晕,真不想多说你们这样的人!
TGITCIC 2008-10-20
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 preferme 的回复:]
5个线程,5个数据库连接,是不会产生楼主所说的问题的。
而且,也没有必要使用synchronized关键字,
因为,按照楼主的思路,应该是每个线程都负责数据处理的整个过程,
只不过,数据来源被拆分了,而已。

我想 , 问题的关键,应该是5个线程使用了同一个连接,使得所产生的rs有关联,关闭一个,其他的就不能够使用。
[/Quote]
自己解决了

CSDN上的人好菜!
冰思雨 2008-10-20
  • 打赏
  • 举报
回复
一般这种数据处理的问题,其瓶颈应该不是在查询速度上,
所以,我给楼主一个参考方案。

内容如下:
1.创建DataBean,对应查询数据的每一条记录。
2.创建一个固定大小的线程安全的阻塞队列,用于存放查询的数据。
3.使用一个线程,对数据库进行查询,将查询数据放入队列。
(这个查询,可以使用如下方式,多次查询,每次只查一部分,各部分数据不重复)
4.创建4~5个线程,用于对查询数据的处理。
(从队列里面取出数据,进行处理即可)
冰思雨 2008-10-20
  • 打赏
  • 举报
回复
5个线程,5个数据库连接,是不会产生楼主所说的问题的。
而且,也没有必要使用synchronized关键字,
因为,按照楼主的思路,应该是每个线程都负责数据处理的整个过程,
只不过,数据来源被拆分了,而已。

我想 , 问题的关键,应该是5个线程使用了同一个连接,使得所产生的rs有关联,关闭一个,其他的就不能够使用。
TGITCIC 2008-10-20
  • 打赏
  • 举报
回复
我的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的关系?
TGITCIC 2008-10-20
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 lifetragedy 的回复:]
自己顶
[/Quote]

你就没看完我的贴,我是在每个线程里用到一个CONNECTION了,怎么没看清就发贴呀!
TGITCIC 2008-10-20
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 sunyujia 的回复:]
CSDN的人是很菜,但是写同样的功能,肯定不用40分钟,谢谢,代码,需求,系统都在你手里面,不再我们手里面,如果你们的系统很行,也不会来这提问解决了。40分钟很快吗?我也不想多说什么,我是比较菜的csdn人。
[/Quote]
成10分钟了,哈哈哈,8小时给我们减到10分钟,原来那批做单线程处理数据的人可以被开除了,什么东西啊!10分钟的东西要做8小时,烂!
java__king 2008-10-19
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 lifetragedy 的回复:]
自己顶
[/Quote]
帮你顶
sunyujia 2008-10-19
  • 打赏
  • 举报
回复
到处都是synchronized 你这多线程几乎提升不了什么速度,比串行快不了哪去
每个线程使用一个conntion即可,在业务上需要同步的地方同步一点点即可。
TGITCIC 2008-10-19
  • 打赏
  • 举报
回复
自己顶
TGITCIC 2008-10-19
  • 打赏
  • 举报
回复
自己顶
TGITCIC 2008-10-19
  • 打赏
  • 举报
回复
哪位大侠能指点迷津啊,痛苦啊!
一会报这个

java.sql.SQLException: The result set is closed.

一会报这个
java.sql.SQLException: operation not allowed before rs
TGITCIC 2008-10-19
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 jumpheightway 的回复:]
每个线程都不要关闭数据库
或者是设置节点
最后一个线程关闭数据库
[/Quote]

怎么个同步法,您能说明白些吗?
TGITCIC 2008-10-19
  • 打赏
  • 举报
回复
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) {
}
}
}

}

}
TGITCIC 2008-10-19
  • 打赏
  • 举报
回复
我每个线程里自己造一个Connection的,我没有把这个Connection方法贴出来而己,不是5个线程公用一个connection,每个线程中都含有connection的新建和打开.

我已经说了,5个线程,造了5个Connection,因为我始终控制好只打开5个CONNECTION,这点我也通过数据库或容器的MONITOR窗口看到了
havelock 2008-10-19
  • 打赏
  • 举报
回复
我靠.才把字打完就看见两个回复了...回复真快
havelock 2008-10-19
  • 打赏
  • 举报
回复
你的conn不是每个方法里面一个.是用的成员~ 从你方法中没有conn
的声明就可以看出来.

而你在每次方法执行的最后有
try {
conn.close();
conn = null;
} catch (Exception e) {
}

connection已经关闭.也就是说resultset也关闭了.是肯定会抛异常的.

加载更多回复(2)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧