我想使用Enumerator
(类似于ScalaStream示例)将数据库结果块化为响应为TSV。我可能有数千行,我不想分页结果,也不想将整个ResultSet
累积到一个String
中。如果需要,块可以不在行分隔符处中断。换句话说,唯一的标准是对结果进行分块,而不是它遵循TSV分隔符。
我想在我的行动中做这样的事情:
Ok.stream(new Iterator[ResultSet] {
val conn = DB.getConnection()
val stmt = conn.createStatement
val rs = stmt.executeQuery("""select * from atable""")
def hasNext = !rs.isLast() && !rs.isClosed()
def next() = {
if (!rs.next()) {
conn.close()
null
} else rs
}
}.toStream)
不幸的是,Ok.stream
期望java.io.InputStream
并且将结果包裹在InputStream
中似乎过度。 Ok.stream
也接受Enumerator
,但我不确定如何在此上下文中创建一个。
答案 0 :(得分:10)
首先,您不能“异步”执行此操作,因为JDBC API是同步的 - 当您调用rs.next()
时,它将同步阻止。但是没关系,只需要确保你的线程池被调整为允许阻塞操作(即,使它们变大)。 Play有一个异步流API(与您最常用的同步InputStream / OutputStream完全不同),它使用称为iteratees / enumerators的东西。您想要创建枚举ResultSet的枚举器。基本上,你想做一些看起来像这样的事情:
import play.api.libs.iteratee._
val conn = DB.getConnection()
val stmt = conn.createStatement
val resultSet = stmt.executeQuery("""select * from atable""")
Ok.stream(Enumerator.unfold(resultSet) { (rs: ResultSet) =>
if (rs.next()) {
val chunk = // Read the result from the ResultSet and format it in the way you want it formatted
Some((rs, chunk))
} else None
}.onDoneEnumerating {
resultSet.close()
stmt.close()
conn.close()
})