3

当我需要使用 JDBC 驱动程序从 PostgreSQL 数据库中读取数百万行数据库时,我总是使用游标,否则我会得到 OutOfMemoryError。这是我使用的模式(伪代码):

begin transaction
execute("declare cursor...")
while (true) {
  boolean processedSomeRows = false
  resultSet = executeQuery("fetch forward...")
  while (resultSet.next()) {
    processedSomeRows = true
    ...
  }
  if (!processedSomeRows) break
}
close cursor
commit

这是我想出在 Scala 中实现的更“功能性”的等价物:

begin transaction
execute("declare cursor...")

@tailrec
def loop(resultSet: ResultSet,
         processed: Boolean): Boolean = {
  if (!resultSet.next()) processed
  else {
    // Process current result set row
    loop(resultSet, true)
  }
}

while (loop(executeQuery("fetch forward..."), false))
  ; //Empty loop

close cursor
commit

我知道这是人为的,但是有没有更好的方法而不诉诸可变性?如果我尝试在 Haskell 中执行此操作,我可能会想出一个涉及 monad 的解决方案,但我不想让我的思绪落入那些“曲折的小段落,都一样”,因为它可能永远不会回来......

4

2 回答 2

0

这是我想出的 Scala 解决方案:

@tailrec
def processCursor(query: => ResultSet)(process: ResultSet => Unit) {
  @tailrec
  def loop(resultSet: ResultSet,
            processed: Boolean): Boolean = {
    if (!resultSet.next()) processed
    else {
      process
      loop(resultSet, true)
    }
  }
  if (loop(query, false)) processCursor(query)(process)
}

像这样称呼它:

begin transaction
execute("declare cursor...")

processCursor(statement.executeQuery("fetch forward...")) {
  resultSet =>
  // process current row of the ResultSet
}

close cursor
commit

如何改进?

于 2012-10-09T12:13:38.477 回答
0

基于@Ralph 答案的替代方法:

  def processCursor[T](resultSet: ResultSet)(process: ResultSet => T) = {
    @tailrec
    def loop(seq: Seq[T], resultSet: ResultSet): Seq[T] = {
      if (resultSet.next()) loop(seq :+ process(resultSet), resultSet)
      else seq
    }
    loop(Seq.empty, resultSet)
  }
于 2015-07-03T07:31:32.087 回答