如何从 jdbc 结果集中返回 java8 Stream

tkr*_*use 5 spring-jdbc java-8 java-stream spring-4

为了充分利用 java8 流和 Spring4,我在来自 Springs jsdbRestTemplate(代码缩短和简化)的 JDBC 结果集上使用了 Stream API,如下所示:

public <T> T consumeResultStream(
    String query, 
    Function<Stream<String>, T> extractorFunction
) {
    return jdbcTemplate.query(
        query, 
        resultSet -> {
            Spliterator<String> spliterator = 
                Spliterators.spliteratorUnknownSize(
                    new Iterator<String>() {
                      @Override public boolean hasNext() {
                        return !resultSet.isAfterLast();
                      }
                      @Override public String next() {
                        String result = resultSet.getString(0);
                        resultSet.next();
                        return result;
                      }
                    }, 
                    Spliterator.IMMUTABLE);
           resultStream = StreamSupport.stream(
               spliterator, /*parallel*/ false);
       }
       return extractorFunction.apply(resultStream);
    });
}
Run Code Online (Sandbox Code Playgroud)

这似乎工作正常。客户端可以像这样使用流 Api 而不必担心 jdbc 类

List<T> myResult = consumeResultStream("SELECT ...", stream -> 
    stream.filter((String s) -> ...)
        .map(String s -> toT(s))
        .collect(toList()));
Run Code Online (Sandbox Code Playgroud)

但是,当我重构时(尝试将流提供给客户端方法),如下所示:

    final Stream<String> stream = 
        jdbcTemplate.query(query, resultSet -> {
          // ... same as above
          return resultStream;
        });
    return extractorFunction.apply(stream);
Run Code Online (Sandbox Code Playgroud)

我得到

org.springframework.jdbc.InvalidResultSetAccessException: 
  The object is already closed [90007-199]
Run Code Online (Sandbox Code Playgroud)

所以看起来数据只能在jdbcTemplate.query()方法内读取。有没有一种干净的方法可以绕过这个并返回来自数据库的元素的惰性流?假设具体化结果和流式传输不是一种选择,因为结果的大小(尽管分页可能是更好的模式)。

dav*_*xxx 0

JdbcTemplate与 Spring 功能相反,它不处理超出其调用的事务JPA
为了不允许关闭数据库连接,请从客户端打开一个事务来操作返回的延迟结果。
通常用注释@Transactional就足够了:

@Transactional
public void findLazyData(){
   Stream<String> result = dataAccessService.find(...);
   // where find() contains the JdbcTemplate invocation
}
Run Code Online (Sandbox Code Playgroud)

请注意包来源:org.springframework.transaction.annotation.Transactional