0

我目前正在开发一个对数据库进行大量工作的项目。

我在代码中多次重复使用的一个核心习惯用法如下。

我的问题是,有没有更好的方法来处理 getTransformedResults 方法的每一步的异常?这是处理 SQLExceptions 的正确方法,还是有更好、更简洁的方法?

感谢您的输入!

public ResultType handleResultSet(ResultSet rs);

public ResultType getTransformedResults(String query) throws SQLException {
  ResultType resultObj = new ResultType();

  Connection connection = null;
  try { 
    connection = dataSource.getConnection();
  } catch (SQLException sqle) {
    // cleanup 
    throw sqle;
  }

  Statement stmt = null;
  try { 
    stmt = connection.createStatement();
  } catch (SQLException sqle) {
    try { connection.close() } catch (SQLException dontCare) {}
    // cleanup
    throw sqle;
  }

  ResultSet rs = null;
  try { 
    ResultSet rs = stmtm.executeQuery(query);
    resultObj = handleResultSet(rs);
  } catch (SQLException sqle) {
    // cleanup
    throw sqle;
  } finally {
    if (rs != null) try { rs.close() } catch (SQLException dontCare) {}
    try { stmt.close() } catch (SQLException dontCare) {}
    try { connection.close() } catch (SQLException dontCare) {}
  }

  return resultObj;
}
4

5 回答 5

1

Java 7 有一些你可能会喜欢的结构,我认为你可以使用 try/finally 而不用 catch(它模仿你的 catch 和 rethrow)。

此外,由于您已经捕获并处理了 SQL 异常,也许您应该将它作为其他东西重新抛出——也许作为运行时异常——这使得在主入口点捕获所有运行时异常变得更容易,而不是必须每次访问数据库时都要处理异常。

于 2012-07-12T16:01:26.003 回答
1

就我个人而言,我可能会通过传入接口实现而不是子类化来处理这个问题。

最终,如果您只处理该方法中的异常,而不污染主线代码,您还能做什么,这样做的意义何在?您可能会使每个步骤更加细化,因此它不是全部在一种方法中,而是除此之外......

您可能会考虑一个特定于应用程序的异常,它可以使测试和配置更清晰,但这取决于上下文。


接口思路的澄清

您将拥有一个实现结果集处理和查询字符串检索的接口,而不是子类化,因此有两种方法——一种用于查询,一种用于结果。

您会将实现传递给您现在拥有的大部分实例,但它采用接口而不是查询字符串。其余代码基本相同,但它从接口impl获取查询字符串,并调用接口impl的结果处理方法,保存结果直到清理。

它与您现在的基本相同,但 IMO 更清洁,因为任何类都可以实现该接口,包括匿名类或您域中的其他类。

于 2012-07-12T16:03:07.083 回答
0

org.springframework.jdbc.core.JdbcTemplate - “...简化了 JDBC 的使用并有助于避免常见错误。”

于 2012-07-12T16:13:07.753 回答
0

您可能对使用完全针对此类目的的Apache Commons DbUtils感兴趣。

在尝试使用更复杂的情况时它有一些缺点,JDBC但对于常规使用它应该绰绰有余。

除此之外,您的代码包含太多的 try/catch 块,可以简化为如下所示:

public interface ResultSetHandler<ResultType> {
     ResultType handleResultSet(ResultSet rs);
}

public <ResultType> ResultType getTransformedResults(String query, ResultSetHandler<ResultType> rsh) throws SQLException {      
  Connection connection = null;
  Statement stmt = null;

  try { 
    connection = dataSource.getConnection();
    stmt = connection.createStatement();
    ResultSet rs = stmtm.executeQuery(query);
    return rsh.handleResultSet(rs);
  } catch (SQLException sqle) {
    // cleanup 
    throw sqle;
  } finally {
    if(stmt != null) {
      statement.close(); // closes also resultSet
      connection.close();
    }
  }
}

尽管 Apache Commons DbUtils 库在底层做的完全一样。

于 2012-07-12T16:13:18.853 回答
0
Connection c = null;
Statement s = null;
ResultSet r = null;

try {
  c = datasource.getConnection();
  s = c.createStatement();
  r = s.executeQuery(sql);
  rsh.handleResultSet(r);
}
finally {
  DbUtils.closeQuietly(r);
  DbUtils.closeQuietly(s);
  DbUtils.closeQuietly(c);
}

注意 DbUtils 是 apaache commons-dbutils,closeQuietly 等价于:

try {
  c.close();
}
catch (SQLException e) {
}

说了这么多,我推荐使用spring的jdbc特性:

JdbcTemplate template = new JdbcTemplate(dataSource);
List data = template.query(sql, new RowMapper() { ... });

RowMapper 是一个接口,其实现的任务是将结果集中的当前位置转换为对象。因此,通过简单地给出如何处理一行的逻辑,您可以自动收集这两行代码中所有行的对象列表以及映射行所需的任何内容。还有其他方法可以让您以不同的方式使用 ResultSet,但这是人们使用它的一种非常标准的方式。

所有的连接和语句管理都为您完成,您完全不用担心资源管理。

于 2012-07-12T16:49:36.450 回答