鉴于rowParser
型RowParser[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 })
}
它的工作原理,但似乎过于复杂。 我当然可以只调用toStream
的List
我从第一功能得到,但我的目标是只适用rowParser
对实际读取的行。 是否有更简单的方法来实现这一目标?
编辑:我知道, limit
应该在查询中使用,如果感兴趣的行数是事先知道的。 我也知道,在很多情况下,你还是要用整个结果,那么懒惰不会提高性能。 但也有可能是在那里你节省几个周期,例如情况下,如果由于某种原因,你有,你不能或不想在SQL来表达搜索条件。 所以,我认为这是奇怪的,因为ANORM提供一种方式来获得的事实Stream
的SqlRow
,我没有找到应用的简单方法RowParser
上。
我结束了创建我自己的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
只能为成功/错误而每一行也可以是成功/错误。 我处理这个问题只在第一行,假设其余的将是相同的。 这可能会或可能不会为你工作。
你最好不要让使用更小的(分页)查询limit
和offset
。
如果你要在内存中保持你的(大)结果,并从那里流呢ANORM需要做一些修改。 那么其他的关注将是你的JVM新的内存需求。 而且你会如何处理对服务级别的缓存? 见,以前你可以轻松缓存类似photos?page=1&size=10
,但现在你只需要photos
,和缓存技术将不知道该怎么做的流。
更糟糕的是,可能在JDBC级,包裹流周围limit
版和offset
-ed execute
语句,只是做给幕后的数据库中的多个电话,但这个听起来就需要工作的公平位端口的流该斯卡拉生成到Java的土地(使用Groovy,JRuby的,等工作)的代码,然后把它在批准了JDBC 5或6的路线图。 这种想法可能会避而远之为太复杂,它是。
你可以换Stream
在你的整个DAO(其中limit
和offset
权术会发生),但是这几乎听起来像更多的麻烦比它的价值:-)
我遇到类似的情况,但遇到了一个调用堆栈溢出异常时,内置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") }
}
有,当然,缺点这种方法,但是,这让周围我的问题,并没有需要包含任何其他库。