您的位置:首页 > 运维架构

JDBC:报错-Operation not allowed after ResultSet closed(一)

2015-06-12 10:55 756 查看
今天遇到一个问题:



下面是数据库操作封装java代码

public static final String DBDRIVER = "org.gjt.mm.mysql.Driver";// 定义MySql的驱动程序
	public static final String DBURL = "jdbc:mysql://localhost:3306/pis";// 定义连接地址
	public static final String DBUSER = "root";// 定义用户名
	public static final String DBPASS = "root";// 定义密码
	Connection conn = null;// 数据库连接
	Statement stmt = null;// 数据操作

	public void  dbGo(){
		
		try {
			Class.forName(DBDRIVER);
		} catch (ClassNotFoundException e1) {
			System.out.println("加载驱动失败T_T");
		}
		try {
			conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
		} catch (Exception e) {
			System.out.println("无法连接至数据库O.O");
		}
		
		try {
			stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
					ResultSet.CONCUR_UPDATABLE);
		} catch (SQLException e1) {
			System.out.println("创建statment失败!");
		}
	}
	
	
	public void dbClose(){
	
				try {
					conn.close();
				} catch (SQLException e) {
					System.out.println("数据库链接conn关闭失败!");
				}
		
	}
	
	public void add(String addSql) throws ClassNotFoundException{
		dbGo();	
		 try {
			stmt.execute(addSql);
		} catch (SQLException e) {
			System.out.println("******************");
			System.out.println("添加失败!错误的sql语句是:"+addSql);
			System.out.println("******************");
		}
		 dbClose();
	}
	
	public ResultSet select(String selectSql) throws ClassNotFoundException{
		dbGo();
		ResultSet rs=null;
		try {
			rs = stmt.executeQuery(selectSql);
		} catch (SQLException e) {
			System.out.println("******************");
			System.out.println("查询失败!错误的sql语句是:"+selectSql);
			System.out.println("******************");	
		}
		dbClose();
		return rs; 
	}


原来是在res使用完毕之前,不能关闭conn。

百度之,一位网友说:

connection或者statement,他们中间是有依赖关系的。

查API,

ResultSet的close方法:



注意 “Note”那段注释:当Satament对象关闭、重新执行或者从一组多个结果集中获取下一个结果时,ResultSet 对象会关闭。

Statment的close方法:



同样说明了 关闭Statment 也会关闭 ResultSet

Connect的close方法:



并没有多说什么。

总体来说还不是明确。

百度之。

找到如下,某位网友的博客。

(1)    主要问题 

针对关闭connection是否会自动关闭Statement和ResultSet的问题,以及Statement和ResultSet所占用资源是否会自动释放问题,JDBC处理规范或JDK规范中做了如下描述: 

JDBC处理规范 

JDBC. 3.0 Specification——13.1.3 Closing Statement Objects 

An applicationcalls the method Statement.close to indicate that it has finished processing astatement. All Statement objects will be closed when the connection thatcreated them is closed. However, it is good coding practice for applications toclose statements as soon as they have finished processing them. This allows anyexternal resources that the statement is using to be released immediately. 

Closing aStatement object will close and invalidate any instances of ResultSet producedby that Statement object. The resources held by the ResultSet object may not bereleased until garbage collection runs again, so it is a good practice toexplicitly close ResultSet objects when they are no longer needed. 

These commentsabout closing Statement objects apply to PreparedStatement and CallableStatementobjects as well. 

JDBC. 4.0 Specification——13.1.4 Closing Statement Objects 

An applicationcalls the method Statement.close to indicate that it has finished processing astatement. All Statement objects will be closed when the connection that createdthem is closed. However, it is good coding practice for applications to closestatements as soon as they have finished processing them. This allows any externalresources that the statement is using to be released immediately. 

Closing aStatement object will close and invalidate any instances of ResultSet producedby that Statement object. The resources held by the ResultSet object may not bereleased until garbage collection runs again, so it is a good practice to explicitlyclose ResultSet objects when they are no longer needed. 

Once aStatement has been closed, any attempt to access any of its methods with theexception of the isClosed or close methods will result in a SQLException beingthrown. 

These commentsabout closing Statement objects apply to PreparedStatement andCallableStatement objects as well. 

规范说明:connection.close 自动关闭 Statement.close 自动导致 ResultSet 对象无效(注意只是 ResultSet 对象无效,ResultSet 所占用的资源可能还没有释放)。所以还是应该显式执行connection、Statement、ResultSet的close方法。特别是在使用connection pool的时候,connection.close 并不会导致物理连接的关闭,不执行ResultSet的close可能会导致更多的资源泄露。 

JDK处理规范: 

JDK1.4 

Note: A ResultSet object is automatically closed by theStatement object that generated it when that Statement object is closed,re-executed, or is used to retrieve the next result from a sequence of multipleresults. A ResultSet object is also automatically closed when it is garbagecollected. 

Note: A Statement object is automatically closed when it isgarbage collected. When a Statement object is closed, its current ResultSetobject, if one exists, is also closed. 

Note: A Connection object isautomatically closed when it is garbage collected. Certain fatal errors alsoclose a Connection object. 

JDK1.5 

Releases this ResultSet object'sdatabase and JDBC resources immediately instead of waiting for this to happenwhen it is automatically closed. 

Note: A ResultSet object isautomatically closed by the Statement object that generated it when thatStatement object is closed, re-executed, or is used to retrieve the next resultfrom a sequence of multiple results. A ResultSet object is also automaticallyclosed when it is garbage collected. 

规范说明: 

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

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

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

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

(2)    解决建议 

(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何时有效。


总结:在1.5之后,虽然垃圾回收机制会自动回收他们,但是因为数据库连接池的问题,Connection对象并未真正的被关闭,所以有必要显示关闭Connection、Stamtent、ResultSet对象。

但是事情还未结束。

针对我一开始写的封装DB操作。如果将三位对象的Close添加进去?一调用这三个方法之后就得不到结果集,这个问题如何解决?

下篇日志再探讨。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: