如何在 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()? @RadhakrishnaSharmaGorentaResultSet
类中没有这种方法
当然,您的第一个参数 sql
可能是一个 PreparedStatementCreator
实现,它已经调用了 next()
,但是当您使用与API而不在您的问题中发布代码。您可以使用返回List
的query
重载之一尝试您的设置。第一行是包含还是缺失?正如已经证明的那样,Springs 拥有 ResultSetExtractor
实现 do 调用 next()
。
您的措辞表明ResultSet
的“合成”性质有所不同。那将是一个非常危险的设置。正如已经多次强调的那样,Springs own ResultSetExtractor
implementations 将调用next()
,如果你设法获得了一个不能正常工作的环境,你应该重新考虑这一点。您的解决方案可能适用于该设置,但这对其他用户没有帮助。
【参考方案1】:
接口的角色似乎有些混淆,我看到一些教程做错了。接口RowMapper
和RowCallbackHandler
分别负责提供一个值。每行产生一个副作用。
因此,他们不负责调用 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);
编辑:此解决方案在标准 mysql
和 Postgresql
实例/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
上被调用?它实际上证明了我所说的,这个回调负责处理整个结果集,因为下次调用它时,它会收到一个新的。
显然您混淆了 rows 和 RowSet
。 RowSet
可以有任意数量的行,而 RowMapper
每行调用一次,换句话说,每次调用都会获得一个新的 row, ResultSetExtractor
不是。 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?