当我想返回 ResultSet 时在哪里关闭 JDBC 连接
当我关闭Connection
时,ResultSet
似乎会自动关闭。 但我想返回ResultSet
并在另一个方法中使用它,然后我不知道在哪里关闭Connection
和PreparedStatement
。
public ResultSet executeQuery(String sql, String[] getValue)
{
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
conn = getConn();
pstmt = conn.prepareStatement(sql);
if (getValue != null)
{
for (int i = 0; i < getValue.length; i++)
{
pstmt.setString(i + 1, getValue[i]);
}
}
rs = pstmt.executeQuery();
} catch (Exception e)
{
e.printStackTrace();
closeAll(conn, pstmt, rs);
}
return rs;
}
我已将 closeAll(conn, pstmt, null);
移至 catch 块中,因为我发现如果将其放入 finally 块中,我会在之前立即丢失我的 rs
它返回。 现在,当我想关闭rs
时,我无法关闭conn
和pstmt
。有什么解决办法吗?
It seems that the ResultSet
will be automatically closed when I close the Connection
.
But I want to return the ResultSet
and use it in another method, then I don't know where to close Connection
and PreparedStatement
.
public ResultSet executeQuery(String sql, String[] getValue)
{
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
conn = getConn();
pstmt = conn.prepareStatement(sql);
if (getValue != null)
{
for (int i = 0; i < getValue.length; i++)
{
pstmt.setString(i + 1, getValue[i]);
}
}
rs = pstmt.executeQuery();
} catch (Exception e)
{
e.printStackTrace();
closeAll(conn, pstmt, rs);
}
return rs;
}
I've moved closeAll(conn, pstmt, null);
into catch block because I found that if I put it in finally block I'll lost my rs
immediately just before it returns.
Now when I want to close the rs
, I can't close the conn
and pstmt
. Is there any solution?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
使用
CachedRowSet
在断开连接后保存信息Use
CachedRowSet
for holding info after disconnecting一种干净的编码方法是传入一个对象,该对象具有接受结果集的回调方法。
您的其他方法使用回调方法及其 resultSet 处理代码创建对象,并将其传递给执行 SQL 的方法。
这样,您的 SQL 和DB 代码保留在其所属位置,您的结果集处理逻辑更接近您使用数据的位置,并且您的 SQL 代码会在需要时进行清理。
One clean way of coding this is to pass in an object that has a callback method that takes a result set.
Your other method creates the object with the callback method with it's resultSet handling code, and passes that to the method that executes the SQL.
That way, your SQL & DB code stays where it belongs, your result set handling logic is closer to where you use the data, and your SQL code cleans up when it should.
您不应该永远将
ResultSet
(或Statement
或Connection
)传递到它们所在的方法块之外的 public 中被收购并关闭以避免资源泄漏。常见的做法是将ResultSet
映射到List
,其中Data
只是表示感兴趣数据的 javabean 对象。这是一个基本示例:
这是一个如何正确处理它的基本示例:
您可以按如下方式使用它:
要了解有关 JDBC 最佳实践的更多信息,您可以找到 这篇基本的启动文章也很有用。
You should never pass
ResultSet
(orStatement
orConnection
) into the public outside the method block where they are to be acquired and closed to avoid resource leaks. A common practice is just to map theResultSet
to aList<Data>
whereData
is just a javabean object representing the data of interest.Here's a basic example:
and here's a basic example of how to handle it correctly:
you can use it as follows:
To learn more about the best practices with JDBC you may find this basic kickoff article useful as well.
按照您现在的方式,连接永远不会关闭,这会在以后(如果不是立即)给您的程序和 RDBMS 带来问题。最好创建一个 Java 类来保存 ResultSet 中的字段并返回该字段。 ResultSet 链接到连接,因此无法返回它并关闭连接。
The way you have it right now, the connection would never close which would cause problems later (if not immediately) for your program and the RDBMS. It would be better to create a Java class to hold the fields from the ResultSet and return that. The ResultSet is linked to the connection, so returning it and closing the connection is not possible.
关闭
Connection
和/或PreparedStatement
后,您将无法使用ResultSet
。因此,您需要将一个要对其进行回调的对象传递到此方法中。
所有清理工作都应该在
finally
块中完成。像这样重写它
You can't use
ResultSet
after you've closedConnection
and/orPreparedStatement
.So, you need to pass an object on which to make a callback into this method.
All cleanup should be done in
finally
blocks.Rewrite it like this
实际上,您自己几乎已经回答了这个问题。在您进行实验时,关闭
Connection
将释放与其关联的 JDBC 资源(至少,事情应该是这样工作的)。因此,如果您想返回
ResultSet
(我稍后会讨论这一点),您需要“稍后”关闭连接。执行此操作的一种方法显然是传递与您的方法的连接,如下所示:问题是我真的不知道您的最终目标是什么以及为什么您需要如此低级的东西,所以我不确定这一点是个好建议。除非您正在编写一个低级 JDBC 框架(请不要告诉我您没有这样做),否则我实际上不建议返回
结果集
。例如,如果您想提供某些业务类,请按照其他人的建议返回一些独立于 JDBC 的对象或它们的集合,而不是结果集
。另请记住RowSet
是
ResultSet
因此,如果您不应该使用ResultSet
那么你不应该使用RowSet
。就我个人而言,我认为您应该使用一些辅助类,而不是重新发明轮子。虽然 Spring 可能有点矫枉过正,并且有一点学习曲线(如果你根本不知道的话,那就太多了),Spring 并不是唯一的方法,我强烈建议看看 Commons DbUtils。更具体地说,请查看
QueryRunner
尤其是这个query()
方法:正如你所看到的,这个方法允许传递
ResultSetHandler
公开了一个回调方法,用于将ResultSets
转换为其他对象,如 z5h 的答案 和 DbUtils 提供了几种实现,只需选择适合您需要的一种即可。另请查看DbUtils
类,例如您可能会发现可以方便地关闭 JDBC 资源的各种DbUnit.close()
。真的,除非你有很好的理由这样做(我很想知道它们),否则不要编写另一个 JDBC 框架,使用现有的解决方案,它会为你减轻一些痛苦,更重要的是,避免一些错误您将受益于经过验证的良好设计。即使对于低级别的东西,也有我们所看到的现有(且简单)的解决方案。至少,检查一下。
Actually, you've almost answered that question yourself. As you experimented, closing the
Connection
will release the JDBC resources associated to it (at least, this is how things should work). So, if you want to return aResultSet
(I'll come back on this later), you need to close the connection "later". One way to do this would be obviously to pass a connection to your method, something like this:The problem is that I don't really know what is your final goal and why you need so low level stuff so I'm not sure this is a good advice. Unless if you are writing a low level JDBC framework (and please, don't tell me you are not doing this), I would actually not recommend returning a
ResultSet
. For example, if you want to feed some business class, return some JDBC-independent object or a collection of them as other have advised instead of aResultSet
. Also bear in mind that aRowSet
is aResultSet
so if you should not use aResultSet
then you should not use aRowSet
.Personally, I think you should use some helper class instead of reinventing the wheel. While Spring may be overkill and has a bit of learning curve (too much if you don't know it at all), Spring is not the only way to go and I strongly suggest to look at Commons DbUtils. More specifically, look at
QueryRunner
and especially thisquery()
method:As you can see, this method allows to pass a
ResultSetHandler
which exposes a callback method to convertResultSets
into other objects as described in z5h's answer and DbUtils provides several implementations, just pick up the one that will suit your needs. Also have a look at the utility methods of theDbUtils
class, for example the variousDbUnit.close()
that you may find handy to close JDBC resources.Really, unless you have very good reasons to do so (and I'd be curious to know them), don't write yet another JDBC framework, use an existing solution, it will save you some pain and, more important, some bugs and you'll benefit from proven good design. Even for low level stuff, there are existing (and simple) solutions as we saw. At least, check it out.
您可以调用
ResultSet.getStatement
来检索Statement
,并调用Statement.getConnection
来检索Connection
。从这些中,您可以编写一个
closeResultSet
实用程序方法,该方法将为您关闭所有 3 个方法,除了ResultSet
之外什么都没有。You can call
ResultSet.getStatement
to retrieve theStatement
, andStatement.getConnection
to retrieve theConnection
.From these you can write a
closeResultSet
utility method that will close all 3 for you, given nothing but theResultSet
.更简洁的方法是使用CachedRowSetImpl。但在 MySQL 5.x+ 上,按名称或标签选择列存在一些错误。
要与 MySQL 一起使用,请使用此版本:
https://stackoverflow.com/a/17399059/1978096
The cleaner way is to use CachedRowSetImpl. But on MySQL 5.x+ there are some bugs with selecting columns by name or label.
For use with MySQL use this version:
https://stackoverflow.com/a/17399059/1978096
您确实不应该在较低级别处理 JDBC。使用像 spring 这样的框架,它会处理您所需的所有
close()
操作。You really shouldn't handle with JDBC at the lower level. Use a framework like spring instead, it will handle all required
close()
operations for you.我建议你做更多类似这样的事情:
I'd recommend that you do something more like this: