JDBC3.0规范中提出了一个新的规范:把Statement也进行缓存(一般是应用服务器厂商实现),这样就可以在不同的connection之间可以共享Statement。所以我个人以为,在释放connection之前,最好先close Statement,这样有利于statement的重用(而且这也是规范所推荐的比较好的编程习惯)。

Statement和PreparedStatement已经将数据库操作封装的很好了,所以我从来不再作一个类完成类似的操作。另外connection资源一定要用完就关。不要返回ResultSet对象,用RowSet代替。

我在oracle中,如果不关statement,最后oracle会报错
ORA-1000: max cursor exceeded.

可以在 v$open_cursor中查询未关闭的cursor.

最好还是用完就关。

有一点应该是统一的吧?那就是:当直接connection.close()的时候java端的st对象资源必定已经被释放了,而在DB端相应的cursor资源也许不会马上释放,不同的DB厂商针对这有情况有不同的资源回收策略。
但问题是:是不是正如oldma所说的那样,我们也可以把DB端的资源回收当作黑盒(或者一个能自我调整的容器)来看待,而不必去关心它的溢出或者阻塞???正如我们现在经常使用的连接池pool一样!!
1)如果是这样的,那么我们可以只处理connection的关闭,因为connection的关闭会自动引起java端的rs、st和pst的关闭,而在DB端,则有cache可以复用这些未被显式释放的cursor资源,使这些资源不至于被挂起;
2)如果不是这样,那么我们必须手工关闭rs、st和pst这些与数据库资源对应的对象来释放DB端的资源,然后在最后关闭conn,因为DB不会聪明地调度这些被挂起的资源,不主动关闭它们会导致DB资源被耗尽。

通过回答这一问题,请大家告诉我,我在发帖的时候写的那个函数在极度频繁被调用时可行吗?因为这个函数不处理任何close()操作,只是根据调用者的connection参数和String参数返回rs给调用者,在调用者的代码的最后会有rs.close()和connection.close()操作,但是肯定不会有st.close()。 那么这个未被显式地close()的st就是我一直不清楚的东西,在非常频繁地被重复这样调用(事实上这样的调用就象out.print()一样多)后,DB端会是怎样一种情况?

对于频繁调用的函数Connecton及Statement绝对要Close,正如其他网友所说,不同的数据库可能有不同的实现,但考虑到重用及数据库的移植等问题,还是Close吧。

有道理!

那种方法肯定有问题,不要说服务器端有什么问题,光客户端就可能出现问题,比如一次循环中,你打开很多次的ResultSet和Statement,这个对象不会立刻被释放的。
还有我前面说了,几种情况:
1、ResultSet不依赖于Connection和Statement,这样你只需要一个Connection和一个Statement,这样你每次可以充用这两个对象,那么你只需要和Connection一样加上对Statement的关闭就可以了,中间的使用者必须自己关闭ResultSet
2、ResultSet依赖于Connection和Statement,这样你必须小心设计中间的过程,在同一个命名空间里不能同时建立两个ResultSet对象。
3、ResultSet依赖于Statement对象,但不依赖于Connection对象,这样,你不关闭Statement可能和第一种情况下不关闭ResultSet一样。

事先声明一句,我不常写数据库的代码。
但是我有个疑惑,根据JAVA DOC,Connection、Statement、ResultSet应该都会在垃圾收集时自动被释放。因此理论上他们不应该会存在资源泄漏问题。可能显式的调用Connection的close能够更快的释放数据库资源,但我认为使用Connection Pool应该是更有效率的做法。但对使用Connection Pool的情况下,是否必须显式的close Connection?Statement和ResultSet应该没有必要显式的释放吧,至少从来没有听说有Statement Pool和ResultSet Pool,这是否意味着他们并不使用DB资源呢?
一切只是我的推测,希望有高人能够提出一个可信的测试方案来推翻或是验证它。

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

摘录自 JDBC. 3.0 Specification,13.1.3 Closing Statement Objects

An application calls the method Statement.close to indicate that it has finished processing a statement. All Statement objects will be closed when the connection that created them is closed. However, it is good coding practice for applications to close statements as soon as they have finished processing them. This allows any external resources that the statement is using to be released immediately.

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

These comments about closing Statement objects apply to PreparedStatement and CallableStatement objects as well.

我觉得你这个方法这样写才比较合理:

public static ResultSet sysSelect(Connection conn,String sql)throws SQLException{
Statement st = null;
try{
st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
return rs;
}catch (SQLException ex){
throw ex;
}finally{
if (null!=st) st.close();
}
}

to glassprogrammer,你说的方法做过测试么,我觉得从原理上说不通。
finally中的st.close()会导致它所产生的resultset实例无效,也就是说方法返回参数的rs在该方法执行完毕的时候就是无效的。不知道我的想法对不对。

根据项目中的实际经验,Statement应该显式地关闭,或许与相应的数据库厂商对数据库资源和JDBC驱动实现有各自的不同,为了避免资源没有被及时释放,在connection关闭之前,显式地关闭Statement是必要的。我的做法是将Connection对象做一个包装,实际上是类似proxy,在获取Statement的时候记录其引用,然后在调用Connection的close方法的时候检查记录的引用中的Statement是否已经关闭,如果没有关闭就调用其close方法关闭,根据实际应用的反馈,效果还不错。

非常感谢大家在这里的建议! 虽然从程序上讲这似乎有点儿钻牛角尖,但这会帮助我理解在高访问频率情况下,代码执行效率的巨大差别!
我个人认为:在一个大吞数据吐量和访问率的信息系统中,其健壮性除了使用某种先进的API库或者架构之外,关键之处在于代码的编写习惯、或者是我们经常使用到的、看似可有可无的某些代码的编写方式上!

to glassprogrammer: 关闭连接后还能使用rs的讨论,我在其他地方看到过类似的讨论,可是我以前在DB2、ORACLE812上测试的结果都是行不通的!不知道你是在哪里设置了这一特性? 不过对于使用conn.createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)的最后一个参数可以做到这一点! 但是这是jdbc3.0里的功能,我现在所在的都是IBM的环境,IBM自带的JDK只相当于sun jre1.3.1的版本,是没有这个功能所以也无法测试。

根据测试,关不关Statement, ResultSet无所谓,只要Connection关闭,自动就关闭掉前两者,如果说Statement, ResultSet没关闭,会使DB端资源不能释放,但Connection.close()事件里就调用了Statement.close()->ResultSet.close(),你再调用Statement.close(),ResultSet.close()一次干什么了?效果不是一样码?至于cursor,我测试了Oracle,SQL2000,只要Connection.close,Cursor就也自动关闭了.
to navyzhu :你肯定其他地方有问题.我做了试验

try{
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
for (int i=0; i<100; i++){
Connection conn = DriverManager.getConnection(
"jdbc:microsoft:sqlserver://Akun:1433;databaseName=bookstore", "sa",
"");
Statement stm = conn.createStatement();
ResultSet rs = stm.executeQuery("Select * from Book");
//stm.close();
conn.close();
}
执行后,在SQL查询分析器里sp_who,不占连接啊.

不好意思,实际上Connection.close只是断开同DB的连接,它实际并没去关闭Statement, ResultSet。之所以说Connection.close后,ResultSet无效,是因为ResultSet的操作之前,会检查连接是否有效。所以如next,first等操作都会出错。其他一些跟数据无关的操作就不会有问题。
一定要close掉ResultSet,否则资源会泄漏,因为ResultSet里有Stream对象,close才会调用Stream.close。至于mysapphire的问题,一个简单的方法就是再调用一下ResultSet.getStatement().close就可以了。不知道其他高手有何其他高见。