我是Scala和Play的新手!编程,但在Django中有大量的Web应用程序经验,以及大量的一般编程经验。
我一直在做一些自己的练习,试图提高我对Play的理解!而这种行为让我完全难过。这是一个更为通用的问题的后续问题:Trying to understand Scala enumerator/iteratees
我正在尝试使用枚举器,Iteratees和Futures来查询数据库。
当我对控制器进行编码时:
def index = Action {
db.withConnection { conn=>
val stmt = conn.createStatement()
val result = stmt.executeQuery("select * from datatable")
val resultEnum:Enumerator[TestDataObject] = Enumerator.generateM {
logger.debug("called enumerator")
result.next() match {
case true =>
val obj = TestDataObject(result.getString("name"), result.getString("object_type"),
result.getString("quantity").toInt, result.getString("cost").toFloat)
logger.info(obj.toJsonString)
Future(Some(obj))
case false =>
logger.warn("reached end of iteration")
stmt.close()
Future(None)
}
}
val consume:Iteratee[TestDataObject,Seq[TestDataObject]] = {
Iteratee.fold[TestDataObject,Seq[TestDataObject]](Seq.empty[TestDataObject]) { (result,chunk) => result :+ chunk }
}
val newIteree = Iteratee.flatten(resultEnum(consume))
val eventuallyResult:Future[Seq[TestDataObject]] = newIteree.run
Ok(Await.result(eventuallyResult,60 seconds))
}
}
我在日志中得到了预期的结果:
10:50:27.765 [ForkJoinPool-3-worker-15] DEBUG TestDataObjectController - called enumerator
10:50:27.856 [ForkJoinPool-3-worker-15] INFO TestDataObjectController - {"name":"thingamajig","objtype":"widget","quantity":200,"cost":3.99}
10:50:27.860 [ForkJoinPool-3-worker-15] DEBUG TestDataObjectController - called enumerator
10:50:27.863 [ForkJoinPool-3-worker-15] INFO TestDataObjectController - {"name":"doofus","objtype":"widget","quantity":900,"cost":1.99}
10:50:27.863 [ForkJoinPool-3-worker-11] DEBUG TestDataObjectController - called enumerator
10:50:27.868 [ForkJoinPool-3-worker-11] INFO TestDataObjectController - {"name":"wotsit","objtype":"widget","quantity":30,"cost":0.49}
10:50:27.868 [ForkJoinPool-3-worker-13] DEBUG TestDataObjectController - called enumerator
10:50:27.871 [ForkJoinPool-3-worker-13] INFO TestDataObjectController - {"name":"foo","objtype":"thingy","quantity":490,"cost":1.49}
10:50:27.871 [ForkJoinPool-3-worker-11] DEBUG TestDataObjectController - called enumerator
10:50:27.871 [ForkJoinPool-3-worker-11] WARN TestDataObjectController - reached end of iteration
我得到了预期的JSON对象(在控制器类中定义了一个隐式转换器,这里没有显示)。
但是,当我尝试使用Action.async:
正确编码时 def index = Action.async {
db.withConnection { conn=>
val stmt = conn.createStatement()
val result = stmt.executeQuery("select * from datatable")
val resultEnum:Enumerator[TestDataObject] = Enumerator.generateM {
logger.debug("called enumerator")
result.next() match {
case true =>
val obj = TestDataObject(result.getString("name"), result.getString("object_type"),
result.getString("quantity").toInt, result.getString("cost").toFloat)
logger.info(obj.toJsonString)
Future(Some(obj))
case false =>
logger.warn("reached end of iteration")
stmt.close()
Future(None)
}
}
val consume:Iteratee[TestDataObject,Seq[TestDataObject]] = {
Iteratee.fold[TestDataObject,Seq[TestDataObject]](Seq.empty[TestDataObject]) { (result,chunk) => result :+ chunk }
}
val newIteree = Iteratee.flatten(resultEnum(consume))
val eventuallyResult:Future[Seq[TestDataObject]] = newIteree.run
eventuallyResult.map { data=> Ok(data)}
}
}
然后枚举器在第一次运行时终止!
[info] play.api.Play - Application started (Dev)
10:53:47.571 [ForkJoinPool-3-worker-13] DEBUG TestDataObjectController - called enumerator
10:53:47.572 [ForkJoinPool-3-worker-13] WARN TestDataObjectController - reached end of iteration
我得到一个空白的JSON数组返回
看来result.next()在两个上下文中表现不同,但我无法弄清楚原因。我想知道是否在并行线程中调用了不同的迭代,但每次运行代码时都会可靠地重现这一点,因此我不认为它是线程并发问题。谢谢你的时间!
答案 0 :(得分:0)
我可能完全错了,但我现在有一个关于发生了什么的理论......
如果我正在使用Action.async,则只有在Action块完成后才会实际评估枚举器回调,因此stmt和result对象已经完成并且不再有效。另一方面,如果我通过使用Await阻止Action直到结果可用(我意识到文档说你不应该这样做),那么Action块的值还没有最终确定,因此我得到预期的结果。
正如我在问题中所说的那样,我仍然试图了解Scala和Play是如何工作的,所以如果你知道的话请发表评论!