Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ssis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Database 在Scala中处理数据库游标的功能_Database_Scala_Functional Programming_Cursor - Fatal编程技术网

Database 在Scala中处理数据库游标的功能

Database 在Scala中处理数据库游标的功能,database,scala,functional-programming,cursor,Database,Scala,Functional Programming,Cursor,当我需要使用JDBC驱动程序从PostgreSQL数据库读取数百万个数据库行时,我总是使用游标,否则会出现OutOfMemoryError。以下是我使用的模式(伪代码): begin transaction execute("declare cursor...") while (true) { boolean processedSomeRows = false resultSet = executeQuery("fetch forward...") while (resultSet.

当我需要使用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中实现这一点,我可能会想出一个涉及单子的解决方案,但我不想让我的思想陷入那些“曲折的小段落,都是一样的”,因为它可能永远不会回来……

我想出了一个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

如何改进这一点?

基于@Ralph answer的替代方法:

  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)
  }

我的直接反应是迭代器[ResultSet]在“process current result set”函数上输入.map(),这将是更干净的解决方案的一部分。。。您拒绝这种方法的原因是什么?我通常使用
Iterator
s或
Stream
s来处理
ResultSet
s,但我想不出停止迭代的方法(
processed
参数)。在迭代器上使用takeWhile,当你放进去的任何函数都变为false时,它就会停止绘制新的值。这个问题实际上是关于在迭代器完成时如何执行清理代码的吗?我必须考虑一下(使用
takeWhile
),看看是否可以终止外部
while
循环。