Java当中的ResultSet

Java当中的ResultSet是什么、干什么用就不多说了,说说我前几天在这里栽的一个跟头。

先上一段测试代码看看问题:

public class TestResult {
	public static void main(String[] args){
		String sql = "select id,username from s_user";
		ResultSet rs = null;
		try{
			rs = execQuery(sql);
			while(rs.next()){
				System.out.println("序号:"+rs.getInt(1)+"\t用户名:"+rs.getString(2));
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			closeResultSet(rs);
		}
	}
	
	/**
	 * 该方法用来执行查询sql
	 * @param sql:要执行查询的sql
	 * @return ResultSet:结果集合
	 * */
	public static ResultSet execQuery(String sql){
		Connection conn=null;//连接
		PreparedStatement  pst= null;
		ResultSet rs=null;
		try{
			conn = com.wjl.C3P0Dao.getConn();
			if(conn!=null){
				pst = conn.prepareStatement(sql);
				rs = pst.executeQuery();
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			System.out.println("1111111111111111");
			closeConn(rs,pst,conn);
		}
		System.out.println("22222222222222");
		return rs;
	}
	
	/**
	 * 资源关闭
	 * @param rs
	 * @param stmt
	 * @param conn
	 */
	public static void closeConn(ResultSet rs, Statement stmt, Connection conn) {
		if (rs != null) {
			try {rs.close();
			} catch (SQLException e){e.printStackTrace();}
		}
		if (stmt != null) {
			try {stmt.close();
			} catch (SQLException e){e.printStackTrace();}
		}

		if (conn != null) {
			try {conn.close();
			} catch (SQLException e) {e.printStackTrace();}
		}
	}
	
	/**
	 * 资源关闭
	 */
	public static void closeResultSet(ResultSet rs) {
		if (rs != null) {
			try {rs.close();
			} catch (SQLException e) {e.printStackTrace();}
		}
	}
}

 以上是一个再寻常不过的JDBC查询代码了,这个代码看似没有问题,但运行起来准报错:You can't operate on a closed ResultSet!!!。因为finally执行在return之前,return之前rs就已经关闭了,自然就无法操作一个已经关闭了的ResultSet了。那我不关闭ResultSet不就完了,于是注释掉closeConn()方法中关闭ResultSet那一段,再执行,依旧报错:You can't operate on a closed ResultSet!!!。这就奇怪了,我明明没有关闭为什么还说关闭了呢,看看网上的解释和处理意见:

JDBC数据库连接池connection关闭后Statement和ResultSet未关闭的问题 写道
规范说明:

1.垃圾回收机制可以自动关闭它们;

2.Statement关闭会导致ResultSet关闭;

3.Connection关闭不一定会导致Statement关闭。

V6使用的是数据库连接池,Connection关闭并不是物理关闭,只是归还连接池,所以Statement和ResultSet有可能被持有,并且实际占用相关的数据库的游标资源,在这种情况下,只要长期运行就有可能报“游标超出数据库允许的最大值”的错误,导致程序无法正常访问数据库。

解决建议:

(1)由于垃圾回收的线程级别是最低的,为了充分利用数据库资源,有必要显式关闭它们,尤其是使用Connection Pool的时候;

(2)最优经验是按照ResultSet,Statement,Connection的顺序执行close;

(3)为了避免由于java代码有问题导致内存泄露,需要在rs.close()和stmt.close()后面一定要加上rs = null和stmt = null;

(4) 如果一定要传递ResultSet,应该使用RowSet,RowSet可以不依赖于Connection和Statement。Java传递的是引用,所以如果传递ResultSet,你会不知道Statement和Connection何时关闭,不知道ResultSet何时有效。

( 引用链接:http://blog.csdn.net/hantiannan/article/details/7904855

根据建议,使用RowSet来代替ResultSet返回数据。

Rowset的使用:http://blog.csdn.net/id19870510/article/details/5988438

RowSet和ResultSet的区别:http://blog.csdn.net/amaryh/article/details/5256090

根据RowSet各个接口的特性,推荐使用CachedRowSet,这个是不与statement和Connection关联的,即使前两个关闭了它已经能用。因此将上面的代码改成使用CachedRowSet来返回数据,代码如下:

public class TestResult2 {
	public static void main(String[] args){
		String sql = "select id,username from s_user";
		CachedRowSetImpl rs = null;
		try{
			rs = execQuery(sql);
			while(rs.next()){
				System.out.println("序号:"+rs.getInt(1)+"\t用户名:"+rs.getString(2));
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			closeCachedRowSet(rs);
		}
	}
	
	/**
	 * 该方法用来执行查询sql
	 * @param sql:要执行查询的sql
	 * @return CachedRowSetImpl:结果集合
	 * */
	public static CachedRowSetImpl execQuery(String sql){
		Connection conn=null;//连接
		PreparedStatement  pst= null;
		ResultSet rs=null;
		CachedRowSetImpl rowset = null;
		try{
			conn = com.wjl.C3P0Dao.getConn();
			if(conn!=null){
				pst = conn.prepareStatement(sql);
				rowset=new CachedRowSetImpl();
				rowset.populate(pst.executeQuery());
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			closeConn(rs,pst,conn);
		}
		return rowset;
	}
	
	/**
	 * 资源关闭
	 * @param rs
	 * @param stmt
	 * @param conn
	 */
	public static void closeConn(ResultSet rs, Statement stmt, Connection conn) {
		......
	}
	
	/**
	 * 资源关闭
	 * @param CachedRowSetImpl rs
	 */
	public static void closeCachedRowSet(CachedRowSetImpl rs) {
		if (rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}

另外,也可以使用Result来代替ResultSet返回数据,具体使用方法可以参考如下链接:

http://www.cnblogs.com/zzlp/p/5120176.html

祝大家好运!

猜你喜欢

转载自1017401036.iteye.com/blog/2383640