【发布时间】:2017-04-18 01:34:42
【问题描述】:
我有一个相当大的结果集(60k+ 记录列),我从数据库中提取并使用 Anorm 进行解析(尽管我可以使用 play 的默认数据访问模块,如果需要,它会返回一个 ResultSet)。我需要将这些结果直接转换并流式传输到客户端(而不是将它们保存在内存中的大列表中),然后将它们直接下载到客户端计算机上的文件中。
我一直在参考 ScalaStream 2.5.x Play 文档的“分块响应”部分中演示的内容。我无法实现它在那里显示的“getDataStream”部分。
我还参考了 ScalaAnorm 2.5.x Play 文档的 Streaming Results 和 Iteratee 部分中演示的内容。我已经尝试将结果作为枚举器传递,就像这里返回的一样:
val resultsEnumerator = Iteratees.from(SQL"SELECT * FROM Test", SqlParser.str("colName"))
进入
val dataContent = Source.fromPublisher(Streams.enumeratorToPublisher(resultsEnumerator))
Ok.chunked(dataContent).withHeaders(("ContentType","application/x-download"),("Content-disposition","attachment; filename=myDataFile.csv"))
但是生成的文件/内容是空的。
而且我找不到任何示例代码或关于如何转换数据服务中返回如下内容的函数的参考:
@annotation.tailrec
def go(c: Option[Cursor], l: List[String]): List[String] = c match {
case Some(cursor) => {
if (l.size == 10000000) l // custom limit, partial processing
else {
go(cursor.next, l :+ cursor.row[String]("VBU_NUM"))
}
}
case _ => l
}
val sqlString = s"select colName FROM ${tableName} WHERE ${whereClauseStr}"
val results : Either[List[Throwable], List[String]] = SQL(sqlString).withResult(go(_, List.empty[String]))
results
变成我可以传递给 Ok.chunked() 的东西。
所以基本上我的问题是,我应该如何将从数据库中获取的每条记录提供到一个流中,我可以对其进行转换并将其作为可以下载到文件的分块响应发送到客户端?
我不想为此使用 Slick。但我可以使用不使用 Anorm 的解决方案,只使用返回原始 java.sql.ResultSet 对象的 play dbApi 对象并使用它。
【问题讨论】:
-
在 Anorm/Play 2.5.x 中无需使用转换后的
Iteratee:github.com/playframework/anorm/blob/master/docs/manual/working/… -
@cchantep 是正确的,您希望使用 Akka Streams 支持而不是 Iteratees(在
anorm-akka2.5.2 中)。不幸的是,一些有用的部分(例如,在完成时获取一个值以允许您关闭数据库连接)仍在 Anorm 2.6.0-SNAPSHOT 中,尚未发布。 -
Iteratee 对资源管理的支持并不好,所以这并没有改变直接使用 Akka 支持更简单的观点。
-
@cchantep 我尝试使用github.com/playframework/anorm/blob/master/docs/manual/working/… 中引用的内容。但是当我尝试将流传递给 Ok.chunked() 时出现错误: [anorm.AkkaStream$ResultSource@30ab92d8] java.sql.SQLException 中的 preStart 期间出错:连接已关闭。你有什么可以解决这个问题或我应该如何处理这个流的建议吗?
-
@Elephantopus 你解决了 Connection is closed 问题了吗?我也有同样的问题。
标签: scala akka-stream playframework-2.5 anorm