如何在 Spring JDBC ResultSetExtractor 中检查 ResultSet 是不是为空? [复制]

Posted

技术标签:

【中文标题】如何在 Spring JDBC ResultSetExtractor 中检查 ResultSet 是不是为空? [复制]【英文标题】:How to check ResultSet for emptiness inside Spring JDBC ResultSetExtractor? [duplicate]如何在 Spring JDBC ResultSetExtractor 中检查 ResultSet 是否为空? [复制] 【发布时间】:2016-09-23 01:03:18 【问题描述】:

似乎ResultSet 空的标准检查在 Spring 的 JDBC ResultSetExtractor 中不起作用。我以以下方式使用它:

    return jdbcTemplate.query(sql, ps -> 
        ps.setLong(1, fooParam1);
        ps.setLong(2, fooParam2);
    , rs -> 
        return rs.getLong(1);
    );

那么在这种模式下检查ResultSet空虚的正确方法是什么?

【问题讨论】:

为什么不使用 rs.hasNext()? @RadhakrishnaSharmaGorenta ResultSet 类中没有这种方法 当然,您的第一个参数 sql 可能是一个 PreparedStatementCreator 实现,它已经调用了 next(),但是当您使用与API而不在您的问题中发布代码。您可以使用返回Listquery 重载之一尝试您的设置。第一行是包含还是缺失?正如已经证明的那样,Springs 拥有 ResultSetExtractor 实现 do 调用 next() 您的措辞表明ResultSet 的“合成”性质有所不同。那将是一个非常危险的设置。正如已经多次强调的那样,Springs own ResultSetExtractor implementations 将调用next(),如果你设法获得了一个不能正常工作的环境,你应该重新考虑这一点。您的解决方案可能适用于该设置,但这对其他用户没有帮助。 【参考方案1】:

接口的角色似乎有些混淆,我看到一些教程做错了。接口RowMapperRowCallbackHandler 分别负责提供一个值。每行产生一个副作用。

因此,他们不负责调用 next(),因为框架将负责推进到下一行而不调用回调,一旦 next() 返回 false,即使推进到第一行也可能发生,在这种情况下,ResultSet 为空。在后一种情况下,query(… RowMapper<T>) 将返回一个空的List,而不调用RowMapper,而query(… RowCallbackHandler) 将什么也不做。

相比之下,ResultSetExtractor 负责处理整个 ResultSet,其中包括适当地调用next()。所以你的问题的前提(“......extractData 的每次调用都会给我新的一行。”)是错误的。所有 JDBC 操作的标准行为是在第一行之前返回 ResultSet,这样第一个 next() 调用要么将当前行指针移动到第一行,要么在 ResultSet 为空时返回 false .因此,如果您期望最多一行,您的查询应该看起来像

return jdbcTemplate.query(sql, ps -> 
        ps.setLong(1, fooParam1);
        ps.setLong(2, fooParam2);
   , rs -> rs.next()? rs.getLong(1): null);

编辑:此解决方案在标准 mysqlPostgresql 实例/Andremoniy/上测试并正常工作。

EDIT-2:这个解决方案绝对正确,并且在任何地方都能正常工作。但是应该注意JdbcTemplate类中有两种不同的方法:

    public <T> T query(String sql, PreparedStatementSetter pss, ResultSetExtractor<T> rse) - 在这个例子中使用它,它总是为rs.getRows() 返回0,确实如此。提供的解决方案对于这种情况是正确的。

    public void query(String sql, PreparedStatementSetter pss, RowCallbackHandler rch) 有另一种类型的第三个参数,代码类似:

    jdbcTemplate.query(sql, ps -> ps.setLong(1, fooParam1); ps.setLong(2, fooParam2); , rs -> System.out.println(rs.getRow()); );

会有不同的工作方式:rs.getRow() 将返回处理行数,如果不存在行,则永远不会调用 processRow 方法(这第二种方法让我感到困惑)。 /Andremoniy/

【讨论】:

对不起,我不能同意你的看法。 ResultSetExractor 每次都给我extractData 新的ResultSet 对象,所以它在内部某处调用next。此外,如果您在extractData() 内多次调用next(),您将提前移动并中断整个队列结果的处理。关于您的评分,我不会否决您的回答,但看起来不正确,抱歉 当然,它每次都会为您提供一个 ResultSet。这如何证明next() 已在ResultSet 上被调用?它实际上证明了我所说的,这个回调负责处理整个结果集,因为下次调用它时,它会收到一个新的。 显然您混淆了 rowsRowSetRowSet 可以有任意数量的行,而 RowMapper 每行调用一次,换句话说,每次调用都会获得一个新的 rowResultSetExtractor 不是。 ResultSetExtractor每个结果调用一次,由新的ResultSet 表示。由于每个调用都代表一个全新的查询,因此无论您多久(或是否)在前一个查询的 ResultSet(同时已关闭)上调用 next() 都无关紧要。 @Andremoniy 你读过ResultSet.getRow() 的JDBC api 文档吗" 注意:对于结果集类型为TYPE_FORWARD_ONLY"的结果集,对getRow 方法的支持是可选的"“SQLFeatureNotSupportedException - 如果 JDBC 驱动程序不支持此方法” @Andremoniy:关于重载,我认为它们确实很不幸。但这就是为什么我在之前的评论中强调“lambda 表达式的形状”,这足以消除歧义。返回值的单个参数 lambda(与 void 不兼容)只能是 ResultSetExtractor。这可能非常微妙,即在您的问题中您使用的是明确的rs -> return rs.getLong(1); ,但是当您将其简化为rs -> rs.getLong(1) 时,它可以与void 兼容,从而丢弃结果,因此可能是RowCallbackHandler也是。

以上是关于如何在 Spring JDBC ResultSetExtractor 中检查 ResultSet 是不是为空? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

spring对JDBC整合的时候,要注意自己写一个映射,继承RowMapper,查询的时候会用到,将返回的ResultSet一条对应一个Employee对象。

在 Spring JDBC 中,如何在语句上设置 RESULT SET HOLDABILITY?

Spring Boot:如何外部化 JDBC 数据源配置?

hibernate中的query 如何能象jdbc中的resultset一样使用

javaWeb_JDBC_ResultSet查询操作

如何从 JDBC ResultSet 中获取列数?