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でこれをやろうとすると、モナドを使った解決策を思いつくかもしれませんが、二度と戻ってこないかもしれないので、それらの「ねじれた小さな通路」に頭を下げたくありません...

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 に答える