强烈建议在使用它们时关闭JDBC对象(连接,语句,结果集)。但是,这会产生大量代码:
Connection conn = null;
Statement stm = null;
ResultSet res = null;
try {
// Obtain connection / statement, get results, whatever...
} catch (SQLException e) {
// ...
} finally {
if (res != null) { try { res.close(); } catch (SQLException ignore) {}}
if (stm != null) { try { stm.close(); } catch (SQLException ignore) {}}
if (conn != null) { try { conn.close(); } catch (SQLException ignore) {}}
}
现在我想通过实现一个辅助函数减少关闭对象的(重复)代码量。它将对象作为参数,并尝试使用反射调用每个对象的方法close()
(如果对象确实有这样的方法)。
public void close(Object... objects) {
for (Object object : objects) {
for (Method method : object.getClass().getMethods()) {
if (method.getName().equals("close")) {
try {
method.invoke(object);
} catch (Exception e) {
e.printStackTrace();
}
break; // break on the methods, go for the next object
}
}
}
}
finally
块可以简化为:
} finally {
close(res, stm, conn);
}
这是一件好事吗?如果不是,原因是什么?是否有“更好”的方式?
答案 0 :(得分:8)
就个人而言,我不会在这种情况下使用反射,当有很多好的方法可以做到这一点而不需要它。以下是您可以做的几件事。
JdbcTemplate
对象,有助于减轻Jdbc编码的冗余。样板代码隐藏在JdbcTemplate
的实现中,因此您可以自由地对您的应用程序执行重要操作。AutoClosable
接口的对象。 Java7方式如下所示:
try (
Connection conn = getConnectionSomehow();
Statement statement = getStatementFromConnSomehow(conn);
) {
//use connection
//use statement
} catch(SomeException ex) {
//do something with exception
}//hey, check it out, conn and statement will be closed automatically! :)
答案 1 :(得分:2)
使用新的AutoCloseable功能和界面在java 7中修复了此问题。
如果您需要在java6中执行此操作,我建议使用aspectj并创建一个注释以包围close调用。
答案 2 :(得分:1)
您不需要Java 7,也不需要AOP或Spring(而且您只需要不需要反射)。你可以反转代码并使用类作为穷人的闭包(伪代码):
public class DbExecutor {
public static void exec(DbAction action) {
Connection conn = null;
try {
action.consume(conn);
} catch (SQLException e) {
// ...
} finally {
if (conn != null) { try { conn.close(); } catch (SQLException ignore) {}}
}
}
}
public class DbAction {
public abstract void consume(Connection conn) throws SQLException;
public static class QueryOne extends DbAction {
public List<String> myAnswer = new ArrayList<String>();
@Override
public abstract void consume(Connection conn) throws SQLException {
Statement stm = conn.prepare(...);
ResultSet res = stm.execute();
while(res.hasNext()) {
myAnswer.add(...);
}
//...
}
}
public static class QueryTwo extends DbAction {...}
}
然后使用它你只需要这样做:
DbAction.QueryOne qAction = new DbAction.QueryOne();
DbExecutor.exec(qAction);
System.out.println("found this many:" + qAction.myAnswer.size());
您从连接管理中解脱出来,您不能忘记关闭,关闭Connection应自动关闭Statement和ResultSet。
请注意,也可以使用匿名内部类,但是获得结果可能比使用此显式方法更有问题。
答案 3 :(得分:0)
关闭conn就足够了,但是首先关闭res是很好的代码风格,其次是stm。