展平从多个JDBC ResultSet生成的流,以防止将所有内容加载到内存中

时间:2013-05-03 16:05:28

标签: scala jdbc stream resultset lazy-evaluation

我得到List[String],我需要分组。对于每个块,我需要运行一个返回List[String]的查询(JDBC)。

我想要的是:

  • 来自不同块的所有结果连接在一个单位列表中
  • 最终的平面列表是非严格集合(以便不在内存中加载整个ResultSet)

这就是我所做的:

Stream生成ResultSet,给定List[String](这是块):

def resultOfChunk(chunk: List[String])(statement: Statement): Stream[String] = {
 //..
  val resultSet = statement.executeQuery(query)
  new Iterator[String] {
    def hasNext = resultSet.next()
    def next() = resultSet.getString(1)
  }.toStream
}

制作最终名单:

val initialList: List[String] = //.. 

val connection = //..
val statement = connection.createStatement
val streams = for {
  chunk <- initialList.grouped(10)
  stream = resultOfChunk(chunk)(statement)
} yield stream

val finalList = streams.flatten

statement.close()
connection.close()

(变量名称旨在证明这一概念)。

它似乎有用,但我有点紧张:

  1. 生成具有for-comprehension的Iterator[Stream]。这是 人们在做什么?
  2. 扁平化说Iterator[Stream](我可以假设他们没有得到评估 压扁?)。
  3. 有什么方法可以在关闭连接和声明后使用最终的List
    比方说,如果我需要做很长时间的操作并且不想在此期间保持连接打开,我有什么选择?
  4. 这段代码是否真的阻止了将整个DB ResultSet一次性加载到内存中(这是我的实际目标)?

1 个答案:

答案 0 :(得分:1)

我将逐一回复:

  1. 当然,为什么不呢。为了便于阅读,您可能需要考虑在for-comprehension中展平。

    val finalList = for {
      chunk  <- initialList.grouped(10)
      result <- resultOfChunk(chunk)(statement)
    } yield result
    
  2. 参见上面的展平。是的,你可以假设它们不会被评估。

  3. Iterator无法重复使用(假设initialList.grouped(10)为您提供迭代器)。但是你可以使用Stream代替Iterator然后,是的,你可以,但是:
    • 必须确保在关闭连接之前对其进行全面评估
    • 将所有数据存储在内存中
  4. 是的,
  5. 根据我所看到的情况,我建议您使用以下内容:

    val finalList = for {
      chunk  <- initialList.grouped(10).toStream
      result <- resultOfChunk(chunk)(statement)
    } yield result
    

    这将为您提供根据需要进行评估的Stream[String](按顺序访问时)。完全评估后,您可以关闭数据库连接并仍然使用它。