如何返回空结果集

时间:2020-11-01 13:47:23

标签: java jdbc

我有以下代码:

 private final ResultSet resultSet;

 public returnResult() {

   if(mycondition){
     resultSet = return Empty;
   }else
   resultSet = statement.executeQuery();

}

不打分贝就返回空结果集的正确方法是什么?

3 个答案:

答案 0 :(得分:0)

这实际上很复杂。您需要一个'dummy'空的ResultSet类,但这过去几乎是不可能的。

关于JDBC的历史记录

如果接口的作者在某些版本升级中添加了新方法,则意味着这是一个向后不兼容的更改:版本更新之前编写的该接口的所有实现现在不再可编译,因为它们没有实现新添加的方法。

通常,java 不会破坏向后兼容性。

因此,用java核心定义的接口(在java.something包中)将永远不会增加新方法,因此您可以将其模拟掉,为其中的每个方法QED编写一个合适的虚拟实现。 / p>

不幸的是,JDBC是不具备的少数几个领域之一-想法是,一定数量的开发人员(数据库供应商)将在{中编写接口的实现。 {1}}程序包,因此,假设所有数据库开发人员都参与其中,则这些接口可以开发新方法。

他们做到了。

但是,我相信,但我找不到对此的任何引用,JDBC团队停止了这样做,而是依赖于或多或少可插入的方法,例如PreparedStatement的java.sql

在这种背景下,您可以选择以下方法:

正常进行虚拟实现

.setObject(idx, value, targetSqlType)

只要ResultSet有大量方法,它将是页面和页面。不幸的是。

使用代理

代理是一种机制,通过它可以编写接口的动态实现:无需为接口中的每个方法都提供一个方法,只需提供一个方法即可:它被赋予方法名称(作为字符串) )和参数(作为对象数组)。这样,您可以为需要知道实际结果的所有方法编写一个大的switch-on-strings块,例如ResultSet的public class DummyResultSet implements java.sql.ResultSet { // an impl of every method here that returns a value // that fits the notion that it has no rows } (不执行任何操作)或first()(执行什么都没有)或close()(返回next()),对于其他任何流入的内容,您只需false

这也方便地意味着,如果ResultSet接口增加了更多的方法,则基于代理的虚拟impl可能会对这些新方法(特别是:引发SQLException)做正确的事情:

throw SQLException

这是如此复杂,难道没有简单的方法吗?

好吧,总是会运行一个实际的查询,保证没有结果:

private static final InvocationHandler dummyResultSetHandler =
  (proxy, method, args) -> {
    switch (method.getName()) {
    case "next":
    case "absolute":
        return false;
    case "afterLast":
    case "beforeFirst":
    case "close":
        return null;
    // you need way more of these, go through the entire list
    // of methods ResultSet has.
    default:
        throw new SQLException("No results");
  };

private static final ResultSet EMPTY_SET =
    java.lang.reflect.Proxy.newProxyInstance(
    ResultSet.class.getClassLoader(),
    new Class[] { ResultSet.class },
    dummyResultSetHandler);

将在大多数数据库引擎中完成这项工作:为您保证空结果集。

但是,不幸的是,这将导致数据库引擎快速往返。

我想要一个不往返的简单解决方案

那么不幸的是你不走运。但是,您可以尝试做的是对代码进行某种程度的重构。例如,您可以返回其他内容,例如结果列表或迭代器,因为“空迭代器”和“空列表”很容易实现。

通常,JDBC API有点低,可以直接使用。当然,您可以做到这一点,但是在JDBC之上构建的抽象仍然可以为您提供SQL的所有强大功能,这些功能要好得多,并且在这里也有帮助:JDBI和JOOQ是您可能要研究的库。 >

答案 1 :(得分:0)

您可以将jOOQ的MockResultSet用于此目的,或者从中汲取灵感。

if (mycondition) {

     // Result is the jOOQ representation of the JDBC ResultSet. You might not have to
     // create it with column information attached to it but your client code may expect
     // a ResultSet with N columns and corresponding data types, even if there's no data
     Result<?> result = DSL.using(DEFAULT).newResult(
         DSL.field("COL1", SQLDataType.INTEGER), 
         DSL.field("COL2", SQLDataType.VARCHAR(10))
     );

     resultSet = new MockResultSet(result);
}
else
     resultSet = statement.executeQuery();

请注意,尽管jOOQ在某些用例中具有双重许可,但在此情况下,可以完全由ASL 2.0许可的jOOQ开源版来完成。

免责声明:我为jOOQ背后的公司工作。

答案 2 :(得分:-1)

在不触及数据库的情况下无法获得空的ResultSet。仅当execute查询不返回任何数据时,您才能获得空的ResultSet。为了避免根据您的情况命中数据库,您可以执行以下操作:

public ResultSet returnResult() {
    ResultSet resultSet = null;
    if(!mycondition) {
        //...
        resultSet = statement.executeQuery();
    }
    return resultSet;
}

请注意,如果不满足您的条件,则将获得ResultSet(空或具有一个或多个记录),并且如果满足您的条件,则函数将返回null