2

我有一个使用 JDBC PreparedStatements 访问数据库的应用程序。为了保持数据访问的通用性,访问数据库的方法大量使用 PreparedStatement setObject 方法(请参阅讨论类似方法的问题)。一些伪代码来说明:

public ResultSet getResultSet(String sql, List<Object> parameters) throws SQLException {

  PreparedStatement preparedStatement = db.getConnection().prepareStatement(sql);

  for(int i = 0; i < parameters.size(); i++) {
    preparedStatement.setObject(i+1, parameters.get(i));
  }

  return preparedStatement.executeQuery();
}

这减少了代码重复,因为 getResultSet(String, List) 可用于执行不同的查询。但是,它也有在运行时抛出 SQLExceptions 的风险。示例情况:

  1. 有人调用 getResultSet("SELECT columnWithVarchar2Type FROM someTable WHERE columnWithVarchar2Type = ?", Arrays.asList(someCustomObject));
  2. db.getConnection().prepareStatement(sql) 返回一个OraclePreparedStatement
  3. PreparedStatement.setObject 抛出 java.sql.SQLException '无效的列类型'

OraclePreparedStatement 的行为可能是合理的;它不知道如何将 someCustomObject 映射到 columnWithVarchar2Type。然而,对于 getResultSet(String, List) 的调用者来说,这是一个惊喜——毕竟,调用者提供了一个带有对象的列表,正如所要求的那样!

问题是:鉴于 PreparedStatement 实现之间的差异,有没有办法在 getResultSet 方法的签名中引入任何编译时安全性,以防止调用者传递将在运行时抛出 SQLExceptions 的参数?

完全的编译时安全当然是不可能的,但是有没有办法使用例如泛型来防止有人传入参数,而这些参数总是会导致 SQLException,而与传递的 SQL 无关?

编辑:这很可能甚至在理论上是不可能的(没有什么能阻止某人实现 PreparedStatement 并决定从不抛出 SQLExceptions 或总是从 setObject() 抛出 SQLExceptions)。但是,很高兴知道 ORM 是如何解决这个问题的。

4

0 回答 0