Java - 重复 sql 任务的设计模式

Java - Design Pattern for repeating sql tasks

我有不同的方法,从数据库中查询不同的数据,但是每个方法的主要结构都是一样的。为了减少代码,我想缩小它,但我不知道该怎么做。我尝试过接口,但无法从内部 class 调用 return 语句。 (它应该是类型安全的!)

结构:

public <special type> getXYdata(some parameters) {
    try (Connection connection = mDataSource.getConnection();
                 Statement statement = connection.createStatement();
                 ResultSet results = statement.executeQuery(... special query ...)
    ) {
        // Handle ResultsSet and return object of a special type.
    } catch (SQLTimeoutException e) {
        throw new ContentManagerException("Query took to long or connection timed out", e);
    } catch (SQLException e) {
        throw new ContentManagerException("Query or parsing its results failed", e);
    }
}

想法:

private interface QHandler<T> {
    String getQuery();
    T handleResultSet(ResultSet set) throws SQLException;
}

然后:

private void executeQuery(QHandler handler) throws ContentManagerException {
    try (Connection connection = mDataSource.getConnection();
        Statement statement = connection.createStatement();
        ResultSet results = statement.executeQuery(handler.getQuery())
    ) {
        handler.handleResultSet(results);
    } catch (SQLTimeoutException e) {
        throw new ContentManagerException("Query took to long or connection timed out", e);
    } catch (SQLException e) {
        throw new ContentManagerException("Query or parsing its results failed", e);
    }
}

但是如果我在我的一个数据方法中调用这个私有方法,我不能 return 来自 handleResultSet() 方法的对象,因为 return 语句会影响这个接口方法.是否有一个选项可以告诉 execiteQuery() 方法处理程序具有哪种 return 类型?

注意:它必须是类型安全的,如果可能的话不要转换!

您的方法不应使用原始 QHandler 类型,而应该是通用的:

private <T> T executeQuery(QHandler<T> handler) throws ContentManagerException {
    try (Connection connection = mDataSource.getConnection();
        Statement statement = connection.createStatement();
        ResultSet results = statement.executeQuery(handler.getQuery())
    ) {
        return handler.handleResultSet(results);
    } catch (SQLTimeoutException e) {
        throw new ContentManagerException("Query took to long or connection timed out", e);
    } catch (SQLException e) {
        throw new ContentManagerException("Query or parsing its results failed", e);
    }
}

请注意,您正在尝试重新发明 Spring 的 JdbcTemplate。您可能会考虑使用它而不是重新发明它。

也许您愿意接受其他解决方案。如果你使用的是 Java 8,你可以这样做:

Interface MyHandler {
  <T> T handle(Connection c);
}

class MyHelperClass {
  public <T> T withConnection(MyHandler handler) {
    try {
      Connection connection = mDataSource.getConnection();
      return handler.handle(connection);
    } catch (...) {
      ...
    } finally {
      ...
    }
  }
}

用法:

Result r = myHelperObject.withConnection(con -> {
  ResultSet results = connection.createStatement().executeQuery(query)
  return new Result(..)
});

这样您就可以使用 lambda 表达式,因此您不需要为您的处理程序接口实现各种新的 类。