在哪里关闭java PreparedStatements和ResultSet?
以代码为例:在哪里关闭java PreparedStatements和ResultSet?,java,jdbc,resource-management,Java,Jdbc,Resource Management,以代码为例: PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.createStatement(myQueryString); rs = ps.executeQuery(); // process the results... } catch (java.sql.SQLException e) { log.error("an error!", e); throw new MyAppExcepti
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.createStatement(myQueryString);
rs = ps.executeQuery();
// process the results...
} catch (java.sql.SQLException e) {
log.error("an error!", e);
throw new MyAppException("I'm sorry. Your query did not work.");
} finally {
ps.close();
rs.close();
}
由于
PreparedStatement.close()
和ResultSet.close()
抛出一个java.sql.SQLException
,因此上面的代码无法编译。那么,我应该在finally子句中添加try/catch块吗?或者将close语句移到try子句中?或者干脆不麻烦调用close?对于文件I/O,我通常会在finally块中添加try/catch。但是,您必须小心不要从finally块抛出任何异常,因为它们将导致原始异常(如果有)丢失
有关数据库连接关闭的更具体示例,请参阅。请勿忽略调用close。这可能会引起问题
我更喜欢将try/catch块添加到finally中。如果您真的要手动运行自己的jdbc,它肯定会变得混乱。finally中的close()需要使用自己的try-catch进行包装,这至少很难看。您不能跳过关闭,尽管当连接关闭时资源将被清除(如果您使用的是池,可能不会立即清除)。实际上,使用框架(例如hibernate)管理数据库访问的一个主要卖点是管理连接和结果集处理,这样您就不会忘记关闭 你可以做一些像这样简单的事情,这至少可以掩盖混乱,并保证你不会忘记一些事情
public static void close(ResultSet rs, Statement ps, Connection conn)
{
if (rs!=null)
{
try
{
rs.close();
}
catch(SQLException e)
{
logger.error("The result set cannot be closed.", e);
}
}
if (ps != null)
{
try
{
ps.close();
} catch (SQLException e)
{
logger.error("The statement cannot be closed.", e);
}
}
if (conn != null)
{
try
{
conn.close();
} catch (SQLException e)
{
logger.error("The data source connection cannot be closed.", e);
}
}
}
然后呢,
finally {
close(rs, ps, null);
}
我用这个
finally
{
if (ps != null) ps.close();
if (rs != null) rs.close();
}
我通常有一个实用方法,可以关闭类似这样的东西,包括注意不要尝试使用空引用执行任何操作 通常,如果
close()
抛出异常,我实际上并不关心,所以我只是记录异常并将其吞下——但另一种选择是将其转换为运行时异常。无论采用哪种方式,我都建议使用一种易于调用的实用方法,因为在许多地方您可能需要这样做
请注意,如果关闭PreparedStatement失败,您当前的解决方案将不会关闭ResultSet-最好使用嵌套的finally块。不要浪费时间编码低级异常管理,请使用更高级的API(如Spring JDBC)或连接/语句/rs对象的自定义包装器,要隐藏凌乱的try-catch-rided代码。在Java 7中,您不应该显式地关闭它们,而应该使用以确保它们已关闭并且异常得到了适当的处理。异常处理的工作原理如下:
Exception in try | Exception in close | Result
-----------------+--------------------+----------------------------------------
No | No | Continue normally
No | Yes | Throw the close() exception
Yes | No | Throw the exception from try block
Yes | Yes | Add close() exception to main exception
| | as "suppressed", throw main exception
private void doEverythingInOneSillyMethod(String key)
throws MyAppException
{
try (Connection db = ds.getConnection()) {
db.setReadOnly(true);
...
try (PreparedStatement ps = db.prepareStatement(...)) {
ps.setString(1, key);
...
try (ResultSet rs = ps.executeQuery()) {
...
}
}
} catch (SQLException ex) {
throw new MyAppException("Query failed.", ex);
}
}
在Java7之前,最好使用嵌套的finally块,而不是测试空引用
我将展示的示例可能看起来很难看,但实际上,设计良好的代码可能不会以相同的方法创建连接、语句和结果;通常,每一层嵌套都涉及将一个资源传递给另一个方法,该方法将其用作另一个资源的工厂。使用这种方法,来自close()
的异常将从try
块内部屏蔽异常。这是可以克服的,但它会导致更混乱的代码,并且需要一个定制的异常类来提供Java7中存在的“抑制”异常链接
Connection db = ds.getConnection();
try {
PreparedStatement ps = ...;
try {
ResultSet rs = ...
try {
...
}
finally {
rs.close();
}
}
finally {
ps.close();
}
}
finally {
db.close();
}
另请注意:
关闭语句对象时,其当前ResultSet对象(如果存在)也将关闭
仅关闭finally中的PreparedStatement就足够了,并且仅当它尚未关闭时。但是,如果您想变得非常特别,请首先关闭ResultSet,而不是在关闭PreparedStatement之后(像这里的一些示例一样,在之后关闭它实际上应该保证出现异常,因为它已经关闭) focus finally子句
finally {
try {
rs.close();
ps.close();
} catch (Exception e) {
// Do something
}
}
我认为你必须修改两点
首先,在fainlly子句中再次使用try&catch
第二,在执行ps.close()之前先执行rs.close()
fly1997@naver.com如果您使用的是Java 7,您可以在实现的类中使用异常处理机制的改进(即PreparedStatement
,Resultset
)
您可能还会发现这个问题很有趣:我知道这是一个老问题,但为了防止有人在寻找答案,java现在有了“资源试用”解决方案
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
可能是一种古老(虽然简单)的做事方式,但它仍然有效:
public class DatabaseTest {
private Connection conn;
private Statement st;
private ResultSet rs;
private PreparedStatement ps;
public DatabaseTest() {
// if needed
}
public String getSomethingFromDatabase(...) {
String something = null;
// code here
try {
// code here
} catch(SQLException se) {
se.printStackTrace();
} finally { // will always execute even after a return statement
closeDatabaseResources();
}
return something;
}
private void closeDatabaseResources() {
try {
if(conn != null) {
System.out.println("conn closed");
conn.close();
}
if(st != null) {
System.out.println("st closed");
st.close();
}
if(rs != null) {
System.out.println("rs closed");
rs.close();
}
if(ps != null) {
System.out.println("ps closed");
ps.close();
}
} catch(SQLException se) {
se.printStackTrace();
}
}
}
基于@erickson的答案,为什么不在一个块中尝试这样做呢
private void doEverythingInOneSillyMethod(String key) throws MyAppException
{
try (Connection db = ds.getConnection();
PreparedStatement ps = db.prepareStatement(...)) {
db.setReadOnly(true);
ps.setString(1, key);
ResultSet rs = ps.executeQuery()
...
} catch (SQLException ex) {
throw new MyAppException("Query failed.", ex);
}
}
请注意,您不需要在try
块中创建ResultSet
对象,因为当PreparedStatement
对象关闭时,ResultSet
会自动关闭
语句对象关闭时,ResultSet对象将自动关闭
生成它的文件将被关闭、重新执行或用于检索下一个文件
由多个结果序列生成的结果
参考:这并不能回答问题-因为ps.close()和rs.close()都可以抛出SqlException。如果将finally放在与右大括号相同的行上,那么就不会那么难看了。;)Ctrl-Shift-F,让您心满意足!;)如果不关闭语句,这是一个坏主意。如果您使用连接池,您的代码将以ORA-01000:超出最大打开游标数而告终
。关闭语句有帮助,因为Oracles通用连接池(UCP)也有语句池。@没有人建议可以避免关闭语句。您在响应什么?@roomsg这是真的,但是如果您使用的是PreparedStatement
,那么ResultSet
对象很可能是在循环中创建的,因此确保它们像这样关闭仍然是很好的代码卫生。如果在关闭准备好的语句之前创建了大量结果集,则仍然可能存在问题,即使它们最终将被关闭。如果您自己滚动,此解决方案效果非常好,因为close方法引发的SQLExceptions无论如何都是不可恢复的。另一种干净利落的方式