我是Scala和Play的新手!編程,但在Django中具有webapps的合理數量的經驗,以及大量的一般編程經驗。奇怪的枚舉器/ iteratee /查詢數據庫時的未來行爲
我一直在做一些我自己的練習,試圖提高我對Play的理解!而這種行爲讓我完全陷入困境。這是一個更一般的後續問題在這裏:Trying to understand Scala enumerator/iteratees
我想查詢數據庫,使用枚舉數,迭代和期貨。
當我編寫這樣我的控制器:
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()是兩個上下文行爲不同,但我不明白爲什麼。我想知道是否在並行線程中調用了不同的迭代,但是每次運行代碼時都可以可靠地再現這些迭代,所以我不希望它成爲線程併發問題。謝謝你的時間!
更好地從最新版本Play 2.5.x開始,它使用的是Akka Streams。 – cchantep
使用'Future.successful('而不是'Future(' – rethab
@rethab - 恐怕沒什麼區別:( –