Java 有没有更好的方法来处理从某个数据源引发的异常?

Java 有没有更好的方法来处理从某个数据源引发的异常?,java,database,exception,jdbc,exception-handling,Java,Database,Exception,Jdbc,Exception Handling,我目前正在从事一个项目,该项目在数据库方面做了大量工作 下面是我在代码中多次重复使用的一个核心习惯用法 我的问题是,在getTransformedResults方法的每个步骤中,是否有更好的方法来处理异常?这是处理SQLExceptions的正确方法,还是有更好、更简洁的方法 谢谢你的意见 public ResultType handleResultSet(ResultSet rs); public ResultType getTransformedResults(String query)

我目前正在从事一个项目,该项目在数据库方面做了大量工作

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

我的问题是,在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;
}

Java7有一些您可能会欣赏的结构,我认为您可以使用try/finally而不使用catch(它模仿您的catch和rethrow)


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

我个人可能会通过传递接口实现而不是子类化来处理这一问题

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

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


界面概念的澄清

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

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


它本质上与您现在使用的相同,但是更干净,因为任何类都可以实现接口,包括匿名类或域中的其他类。

-“…简化了JDBC的使用,并有助于避免常见错误。”

您可能会感兴趣,使用它正是为了实现这些目的

在尝试使用更复杂的
JDBC
时,它有一些缺点,但对于常规使用来说,它应该已经足够了

此外,您的代码包含太多的try/catch块,可以简化为以下内容:

公共接口结果处理程序{
结果类型HandlerResultSet(结果集rs);
}
public ResultType getTransformedResults(字符串查询,ResultSetHandler rsh)引发SQLException{
连接=空;
语句stmt=null;
试试{
connection=dataSource.getConnection();
stmt=connection.createStatement();
ResultSet rs=stmtm.executeQuery(查询);
返回rsh.HandlerResultSet(rs);
}捕获(SQLException sqle){
//清理
抛出sqle;
}最后{
如果(stmt!=null){
语句.close();//同时关闭结果集
connection.close();
}
}
}
尽管ApacheCommonsDbutils库在幕后也做了同样的事情

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是Apache commons DbUtils,其值等效于:

try {
  c.close();
}
catch (SQLException e) {
}
综上所述,我建议使用spring的jdbc特性:

JdbcTemplate template = new JdbcTemplate(dataSource);
List data = template.query(sql, new RowMapper() { ... });
RowMapper是一个接口,其实现的任务是将resultset中的当前位置转换为对象。因此,只要简单地给它一行的处理逻辑,就可以自动收集这两行代码中所有行的对象列表,以及映射行所需的一切。还有其他方法可以让您以不同的方式使用ResultSet,但这是人们使用它的一种相当标准的方式


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

这与JDBC一样好……您通常会看到人们将其压缩为一个try语句。此外,您正在关闭创建语句时使用的连接。您的语句可能无法执行。ps:除非您的数据源正在抑制关闭操作(在大多数池数据源中都会发生),否则它无法执行。您能详细说明传入接口实现的情况吗?你会如何在上面的案例中使用它?就像界面的想法一样。我看了一下ApacheCommonsDbutils,它似乎使用了相同的想法。@JoseChavez Yep。当有很多相对通用的样板文件时,这是一个非常典型的模式,对于JDBC来说,它可能已经实现了数百或数千次!如果您只是执行数据库插入/更新/删除,那么使用JdbcTemplate非常好。但是,如果我同时使用另一个事务源(比如JMS或另一个数据源),我将如何使用JdbcTemplate控制整个事务?按照上面示例中打开和关闭连接的方式,您无论如何都不会参与JTA事务,因此我不确定您的代码示例是否存在问题。如果您想要JTA,那么您必须完全使用spring,并使用它的声明性事务管理和JmsTemplate等。。。与JdbcTemplate一起使用。您必须确保获得dao/jms层的启用事务的代理实例。PS:更不用说JTA是一个复杂的野兽(您必须有一个启用XA的数据源、驱动程序和数据库,然后才能考虑它),您的问题根本就没有提到这一点。如果你有关于JTA的问题,试试谷歌搜索,如果你不能开始,那就另外问一个问题。明白了!我们使用Spring进行简单的查询,但我们也进行涉及多个数据源的事务。我们已经用JTA探索了XA数据源,它们对se来说有点痛苦
JdbcTemplate template = new JdbcTemplate(dataSource);
List data = template.query(sql, new RowMapper() { ... });