并发时出现的 java.sql.SQLException: 关闭的 Resultset: next

heliang69 2010-08-15 04:49:40
程序如果有几十个并发数的时候,会出现“java.sql.SQLException: 关闭的 Resultset: next”的异常。
这个异常一般会是因为在rs.next()之前就关闭了Statement对象才会有的。
但是,程序如果在单线程的情况下就没有此问题,不知道大家有什么解决的办法来避免这个问题,部分代码如下:

//conn为Connection对象。在整个的程序中,是一个静态变量
stmt = conn.createStatement();

rsRow = stmt.executeQuery(strSQL);

// 获取记录
while (rsRow.next()) { //程序在此处报错
stateList.add(rsRow.getString("execute_state"));
}
rsRow.close();
stmt.close();
rsRow = null;
stmt = null;


异常信息:

java.sql.SQLException: 关闭的 Resultset: next
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:146)
at oracle.jdbc.driver.OracleResultSetImpl.next(OracleResultSetImpl.java:175)
at weblogic.jdbc.wrapper.ResultSet_oracle_jdbc_driver_OracleResultSetImpl.next()Z(Unknown Source)
at com.ngoss.framework.db.impl.WorkorderDAOImpl.selectWorkOrder(WorkorderDAOImpl.java:347)
at com.ngoss.framework.impl.RequestManagerImpl.selectWorkOrder(RequestManagerImpl.java:110)



...全文
2383 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
go_all_out 2010-08-20
  • 打赏
  • 举报
回复
首先对于一开始的问题,个人觉得火龙果说的是正确的
至于说在高并发情况下连接池中的链接没法获取到,这个不管用什么连接池都一样,也是正常的
正常连接池的连接数也不可能开太多,用完了,其他的请求当然要等待,直到有连接可用

我想你如果有如此高的并发的话,问题就不是连接池能解决的了,可以考虑负载均衡,集群等方式来解决,一台机器肯定是解决不了了
heliang69 2010-08-18
  • 打赏
  • 举报
回复
重新顶起来
heliang69 2010-08-17
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 bao110908 的回复:]

普通应用程序根本没必要把那三个对象弄成是成员变量,更不可弄成静态的成员变量。只有在数据库连接池的实现中,会将这些对象置于成员变量中,但是连接池的实现者已经进行必要的同步处理,而且还经过严格的性能及压力测试。

但我想不通的是,为什么就有那么多人不遵照普遍的 JDBC 代码,而是喜欢自作聪明呢?

普通的 JDBC 代码结构是这样的:

Java code
Connection co……
[/Quote]


首先,很感谢你的回复。

现在已经代码改回每一次请求从数据库里重新拿Connection,但是遇到了,在高并发的时候,连接池里面的连接数会快速增加的情况。并且我通过在数据库端用SQL语句查询的时候,也发现连接数保持在很高的位置。
我在申请连接与释放连接的地方也都做了同步的操作,并且在这个位置也加了一个记数器来测试,可以肯定是在申请后的连接均释放了。
这种情况在单线程跑的时候,不会出现,查询连接数,很快会回到原始数量。

所以,请问一下,连接池里面的连接数怎么样才能让他马上回恢到原始数量,因为在高并发的时候,很容易发现在连接池的连接数会大量的增加之后,再过来的请求就一直在排除等待拿Connection直至事务超时。
heliang69 2010-08-17
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 bao110908 的回复:]

引用 14 楼 heliang69 的回复:
现在已经代码改回每一次请求从数据库里重新拿Connection,但是遇到了,在高并发的时候,连接池里面的连接数会快速增加的情况。并且我通过在数据库端用SQL语句查询的时候,也发现连接数保持在很高的位置。
我在申请连接与释放连接的地方也都做了同步的操作,并且在这个位置也加了一个记数器来测试,可以肯定是在申请后的连接均释放了。
这种情况在单线程跑的……
[/Quote]

肯定是按照套路出牌了,呵呵。我说的做的那个计数器,也规零了。
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 heliang69 的回复:]
现在已经代码改回每一次请求从数据库里重新拿Connection,但是遇到了,在高并发的时候,连接池里面的连接数会快速增加的情况。并且我通过在数据库端用SQL语句查询的时候,也发现连接数保持在很高的位置。
我在申请连接与释放连接的地方也都做了同步的操作,并且在这个位置也加了一个记数器来测试,可以肯定是在申请后的连接均释放了。
这种情况在单线程跑的时候,不会出现,查询连接数,很快会回到原始数量。

所以,请问一下,连接池里面的连接数怎么样才能让他马上回恢到原始数量,因为在高并发的时候,很容易发现在连接池的连接数会大量的增加之后,再过来的请求就一直在排除等待拿Connection直至事务超时。
[/Quote]

重新拿了,但是你关了没有?如果不按标准的套路走,那只能抱歉,帮不了你。
  • 打赏
  • 举报
回复
普通应用程序根本没必要把那三个对象弄成是成员变量,更不可弄成静态的成员变量。只有在数据库连接池的实现中,会将这些对象置于成员变量中,但是连接池的实现者已经进行必要的同步处理,而且还经过严格的性能及压力测试。

但我想不通的是,为什么就有那么多人不遵照普遍的 JDBC 代码,而是喜欢自作聪明呢?

普通的 JDBC 代码结构是这样的:

Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = ConnectionFactory.getConnection();
String sql = "xxxx";
ps = con.preparedSatement(sql);
ps.setXxxxx(1, xxx);
rs = ps.executeQuery();
while(rs.next()) {
Xxxx xxx = rs.getXxxx();
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (rs != null) try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }
if (ps != null) try { ps.close(); } catch (SQLException e) { e.printStackTrace(); }
if (con != null) try { con.close(); } catch (SQLException e) { e.printStackTrace(); }
}


千万别在 JDBC 上自作聪明,在并发很高的情况下,可能会带来灾难性的后果。
  • 打赏
  • 举报
回复
严禁将 Connection、Statement、ResultSet 等数据库连接对象作为共享变量!

这句话,我在 CSDN Java 版说过不下十次了,但是没有人理会,哎!

JDBC 规范并未规定那三个对象必须是线程安全的,因此所有的 JDBC 厂商也不会去弄成线程安全的,正因为如此,所以就会有并发问题。

如果你对 JDBC、多线程编程没有达到非常熟练的程度,还是老老实实地使用经典的 JDBC 代码结构。
  • 打赏
  • 举报
回复
严禁将 Connection、Statement、ResultSet 等数据库连接对象作为共享变量!后果不用说了,楼主已经尝到了。

解决方案:将共享的数据库连接对象全部改为局部变量。

dr_lou 2010-08-16
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 heliang69 的回复:]
引用 2 楼 ticmy 的回复:
并发的程序,你还敢搞个静态的Connection?连接池是最好的选择


放在静态的目的就是为了防止连接池的溢出的情况,因为,有可能并发数要在1W以上,如果这样的话,那么连接池要如果来配置呢?所以,才放到一个静态的变量里,来解决这个连接池会溢出的问题。
[/Quote]

连接池的参数可以控制排队的,不会溢出吧。
ronniegxq 2010-08-16
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 bao110908 的回复:]

严禁将 Connection、Statement、ResultSet 等数据库连接对象作为共享变量!

这句话,我在 CSDN Java 版说过不下十次了,但是没有人理会,哎!

JDBC 规范并未规定那三个对象必须是线程安全的,因此所有的 JDBC 厂商也不会去弄成线程安全的,正因为如此,所以就会有并发问题。

如果你对 JDBC、多线程编程没有达到非常熟练的程度,还是老老实实地使……
[/Quote]
liuyuhua0066 2010-08-16
  • 打赏
  • 举报
回复
果哥犀利,So right[Quote=引用 10 楼 bao110908 的回复:]
普通应用程序根本没必要把那三个对象弄成是成员变量,更不可弄成静态的成员变量。只有在数据库连接池的实现中,会将这些对象置于成员变量中,但是连接池的实现者已经进行必要的同步处理,而且还经过严格的性能及压力测试。

但我想不通的是,为什么就有那么多人不遵照普遍的 JDBC 代码,而是喜欢自作聪明呢?

普通的 JDBC 代码结构是这样的:


Java code
Connection c……
[/Quote]
xiaomowen_74839 2010-08-16
  • 打赏
  • 举报
回复
火龙果这个好,呵呵
heliang69 2010-08-15
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 ticmy 的回复:]
并发的程序,你还敢搞个静态的Connection?连接池是最好的选择
[/Quote]

放在静态的目的就是为了防止连接池的溢出的情况,因为,有可能并发数要在1W以上,如果这样的话,那么连接池要如果来配置呢?所以,才放到一个静态的变量里,来解决这个连接池会溢出的问题。
heliang69 2010-08-15
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 kokobox 的回复:]
你为什么在遍历结果集之前关闭Statement?

这些最好都放在finally中处理。
[/Quote]

我没有在遍历之前关闭呀。。。。。。。。。。。。。
是在遍历之后关闭的。放在finally里是可以,但是和这个效果一样,还是会报一样的错误
龙四 2010-08-15
  • 打赏
  • 举报
回复
并发的程序,你还敢搞个静态的Connection?连接池是最好的选择
kokobox 2010-08-15
  • 打赏
  • 举报
回复
你为什么在遍历结果集之前关闭Statement?

这些最好都放在finally中处理。

import java.sql.*; import jdbc.DBManager; import jdbc.DBManagerTest; /** *

Title:

*

Description:

*

Copyright: Copyright (c) 2002

*

Company:

* @author * @version 1.0 */ /** * DBManager示例程序 */ public class Test { public Test() { } public static void main(String[] args) { DBManagerTest DBManagerTest1 = new DBManagerTest(); DBManager db_manager = new DBManager(); ResultSet result = null; // 数据库查询结果 try { db_manager.connect("rcms"); // 建表 db_manager .execute("create table table22 (c1 varchar(32) not null,c2 varchar(21))"); } catch (SQLException x) { x.printStackTrace(); try { db_manager.disconnect(); } catch (SQLException e) { // TODO 自动生成 catch 块 e.printStackTrace(); } System.err.print("数据库操作失败!"); } try { // 表更新操作,包括insert,update,delete db_manager .executeUpdate("insert into table22 (c1,c2) values('workflow1','engine1')"); db_manager .executeUpdate("insert into table22 (c1,c2) values('workflow2','engine2')"); db_manager .executeUpdate("insert into table22 (c1,c2) values('workflow3','engine3')"); db_manager .executeUpdate("insert into table22 (c1,c2) values('workflow4','engine4')"); db_manager.beginTransaction(); // for(int i=1500;i<2000;i++){ //// db_manager.executeUpdate("insert into T_USER (USER_ID, USER_NAME, ORG_ID, PASSWD, OLD_PASSWD, STATION, CREAT_DATE, CREAT_TIME, ALTER_DATE, ALTER_TIME, DEL_DATE, TEL, EMAIL, STATUS, SEX, ACADEMIC, CERTI_TYPE, CERTI, FAX, ADRESS, POSTCODE, BAK1, BAK2, BAK3, BAK4, BAK5)values ('test00"+i+"', 'test00"+i+"', '0001 ', 'FF5E61835C355E755EEF9321 ', 'A43B59E342F86CEE5EEF9321 ', '0 ', '20071201', '101010', null, null, null, null, null, '1', null, null, null, null, null, null, null, null, null, null, null, null)"); // db_manager.executeUpdate("insert into T_USER_ROLE values('test00"+i+"','sys_admin','')"); // if(i%300==0)db_manager.commitTransaction(); // } } catch (SQLException x) { x.printStackTrace(); try { db_manager.disconnect(); } catch (SQLException e) { // TODO 自动生成 catch 块 e.printStackTrace(); } System.err.print("数据库操作失败!"); } try { // 表查询操作,返回结果集存在DBResult类中,DBResult中的数据库查询结果已与数据库断开连接了, // 不能动态更新,注意在并发操作中应重新执行表查询操作 result = db_manager.executeQuery("select * from table22"); } catch (SQLException x) { x.printStackTrace(); try { db_manager.disconnect(); } catch (SQLException e) { // TODO 自动生成 catch 块 e.printStackTrace(); } System.err.print("数据库操作失败!"); } // int rows = result.getRows(); //返回的记录数 try { while (result.next()) { String s = result.getString("c1");// 取第4条记录c1的字段 System.out.println(s); s = result.getString("c2"); System.out.println(s); } } catch (SQLException e) { // TODO 自动生成 catch 块 e.printStackTrace(); } } }

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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