有没有更好的方法来处理从某些DataSource抛出的异常?

时间:2012-07-12 15:55:53

标签: java database exception jdbc exception-handling

我目前正在开发一个与Database做很多工作的项目。

我在代码中多次重复使用的一个核心习惯是以下内容。

我的问题是,有没有更好的方法来处理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;
}

5 个答案:

答案 0 :(得分:1)

Java 7有一些你可能会欣赏的结构,我认为你可以使用try / finally而不使用catch(它模仿你的捕获和重新抛出)。

此外,由于您已经捕获并处理了SQL异常,因此您可能应该将其作为其他东西重新抛出 - 可能作为运行时异常 - 这样可以更容易地捕获主入口点处的所有运行时异常而不是每次访问数据库时都要处理异常。

答案 1 :(得分:1)

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

最终,如果您只处理该方法中的异常,而不是污染主线代码,那么您还能做什么,以及这样做的重点是什么?您可能会使每个步骤更加细化,因此不是所有方法都在一个方法中,而是除了...

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


界面理念的澄清

而不是子类化,你有一个实现结果集和查询字符串检索处理的接口,所以有两个方法 - 一个用于查询,一个用于结果。

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

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

答案 2 :(得分:0)

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

答案 3 :(得分: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库的功能完全相同。

答案 4 :(得分: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,但这是人们使用它的一种非常标准的方式。

所有连接和语句管理都是为您完成的,您根本不必担心资源管理。