-->

有一种简单的方法来得到一个流作为RowParser的输出?(Is there an easy way

2019-08-02 10:39发布

鉴于rowParserRowParser[Photo] ,这是你将如何解析从表来行的列表photo ,根据到目前为止,我所看到的代码示例:

def getPhotos(album: Album): List[Photo] = DB.withConnection { implicit c =>
  SQL("select * from photo where album = {album}").on(
    'album -> album.id
  ).as(rowParser *)
}

*运算符创建类型的解析器ResultSetParser[List[Photo]] 。 现在,我在想,如果是同样可以拿到产生一个解析器Stream (以为是比较懒惰总是更好),但我只想到了这一点:

def getPhotos(album: Album): Stream[Photo] = DB.withConnection { implicit c =>
  SQL("select * from photo where album = {album}").on(
    'album -> album.id
  )() collect (rowParser(_) match { case Success(photo) => photo })
}

它的工作原理,但似乎过于复杂。 我当然可以只调用toStreamList我从第一功能得到,但我的目标是只适用rowParser对实际读取的行。 是否有更简单的方法来实现这一目标?

编辑:我知道, limit应该在查询中使用,如果感兴趣的行数是事先知道的。 我也知道,在很多情况下,你还是要用整个结果,那么懒惰不会提高性能。 但也有可能是在那里你节省几个周期,例如情况下,如果由于某种原因,你有,你不能或不想在SQL来表达搜索条件。 所以,我认为这是奇怪的,因为ANORM提供一种方式来获得的事实StreamSqlRow ,我没有找到应用的简单方法RowParser上。

Answer 1:

我结束了创建我自己的stream对应的方法list方法:

def stream[A](p: RowParser[A]) = new ResultSetParser[Stream[A]]  {
      def apply(rows: SqlParser.ResultSet): SqlResult[Stream[A]] = rows.headOption.map(p(_)) match {
        case None => Success(Stream.empty[A])
        case Some(Success(a)) => {
          val s: Stream[A] = a #:: rows.tail.flatMap(r => p(r) match {
            case Success(r) => Some(r)
            case _ => None
          })  

          Success(s)
        }
        case Some(Error(msg)) => Error(msg)
      }
   } 

需要注意的是播放SqlResult只能为成功/错误而每一行也可以是成功/错误。 我处理这个问题只在第一行,假设其余的将是相同的。 这可能会或可能不会为你工作。



Answer 2:

你最好不要让使用更小的(分页)查询limitoffset

如果你要在内存中保持你的(大)结果,并从那里流呢ANORM需要做一些修改。 那么其他的关注将是你的JVM新的内存需求。 而且你会如何处理对服务级别的缓存? 见,以前你可以轻松缓存类似photos?page=1&size=10 ,但现在你只需要photos ,和缓存技术将不知道该怎么做的流。

更糟糕的是,可能在JDBC级,包裹流周围limit版和offset -ed execute语句,只是做给幕后的数据库中的多个电话,但这个听起来就需要工作的公平位端口的流该斯卡拉生成到Java的土地(使用Groovy,JRuby的,等工作)的代码,然后把它在批准了JDBC 5或6的路线图。 这种想法可能会避而远之为太复杂,它是。

你可以换Stream在你的整个DAO(其中limitoffset权术会发生),但是这几乎听起来像更多的麻烦比它的价值:-)



Answer 3:

我遇到类似的情况,但遇到了一个调用堆栈溢出异常时,内置ANORM功能转换成流试图解析结果集。

为了解决这个问题我选择放弃ANORM ResultSetParser范式,并回落到java.sql.ResultSet中的对象。

我想用ANORM的内部类的解析结果集中的行,但是,自从2.4版本,他们已经做了一切私人相关的类和方法,以他们的包,并提倡使用的将是更直接的其他几个方法使用。

我曾经承诺及期货的组合来解决该ANORM现在返回ManagedResource为。 我逃避了被废弃的函数。

import anorm._
import java.sql.ResultSet
import scala.concurrent._

def SqlStream[T](sql:SqlQuery)(parse:ResultSet => T)(implicit ec:ExecutionContext):Future[Stream[T]] = {
  val conn = db.getConnection()
  val mr = sql.preparedStatement(conn, false)
  val p = Promise[Unit]()
  val p2 = Promise[ResultSet]()
  Future {
    mr.map({ stmt =>
      p2.success(stmt.executeQuery)
      Await.ready(p.future, duration.Duration.Inf)
    }).acquireAndGet(identity).andThen { case _ => conn.close() }
  }
  def _stream(rs:ResultSet):Stream[T] = {
    if (rs.next()) parse(rs) #:: _stream(rs)
    else {
      p.success(())
      Stream.empty
    }
  }
  p2.future.map { rs =>
    rs.beforeFirst()
    _stream(rs)
  }
}

此功能的相当琐碎的用法是这样的:

def getText(implicit ec:ExecutionContext):Future[Stream[String]] = {
  SqlStream(SQL("select FIELD from TABLE")) { rs => rs.getString("FIELD") }
}

有,当然,缺点这种方法,但是,这让周围我的问题,并没有需要包含任何其他库。



文章来源: Is there an easy way to get a Stream as output of a RowParser?