像Scala流一样处理SQL ResultSet

Ral*_*lph 43 scala resultset stream

当我查询数据库并接收(仅向前,只读)ResultSet时,ResultSet就像一个数据库行列表.

我试图找到一些方法来像Scala一样对待这个ResultSet Stream.这将允许这样的操作的filter,map等等,而不是消耗大量的内存.

我实现了一个尾递归方法来提取单个项目,但是这要求所有项目同时在内存中,如果ResultSet非常大,则会出现问题:

// Iterate through the result set and gather all of the String values into a list
// then return that list
@tailrec
def loop(resultSet: ResultSet,
         accumulator: List[String] = List()): List[String] = {
  if (!resultSet.next) accumulator.reverse
  else {
    val value = resultSet.getString(1)
    loop(resultSet, value +: accumulator)
  }
}
Run Code Online (Sandbox Code Playgroud)

elb*_*ich 73

我没有测试它,但为什么它不起作用?

new Iterator[String] {
  def hasNext = resultSet.next()
  def next() = resultSet.getString(1)
}.toStream
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很酷的解决方案,但我担心.我认为`Iterator`的通常合同是`hasNext`是无副作用的.在两次调用"next"之间可以调用任意次数.有什么东西阻止这成为一个问题吗? (7认同)

hra*_*ban 10

@ elbowich答案的效用函数:

def results[T](resultSet: ResultSet)(f: ResultSet => T) = {
  new Iterator[T] {
    def hasNext = resultSet.next()
    def next() = f(resultSet)
  }
}
Run Code Online (Sandbox Code Playgroud)

允许您使用类型推断.例如:

stmt.execute("SELECT mystr, myint FROM mytable")

// Example 1:
val it = results(stmt.resultSet) {
  case rs => rs.getString(1) -> 100 * rs.getInt(2)
}
val m = it.toMap // Map[String, Int]

// Example 2:
val it = results(stmt.resultSet)(_.getString(1))
Run Code Online (Sandbox Code Playgroud)


Jer*_*ert 8

对于一个隐含的课程来说,这听起来像是一个很好 首先在某处定义隐式类:

import java.sql.ResultSet

object Implicits {

    implicit class ResultSetStream(resultSet: ResultSet) {

        def toStream: Stream[ResultSet] = {
            new Iterator[ResultSet] {
                def hasNext = resultSet.next()

                def next() = resultSet
            }.toStream
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

接下来,只需在执行查询的任何位置导入此隐式类,并定义ResultSet对象:

import com.company.Implicits._
Run Code Online (Sandbox Code Playgroud)

最后使用toStream方法获取数据.例如,获取所有ID,如下所示:

val allIds = resultSet.toStream.map(result => result.getInt("id"))
Run Code Online (Sandbox Code Playgroud)