2016-09-27 51 views
0

我是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()是兩個上下文行爲不同,但我不明白爲什麼。我想知道是否在並行線程中調用了不同的迭代,但是每次運行代碼時都可以可靠地再現這些迭代,所以我不希望它成爲線程併發問題。謝謝你的時間!

+0

更好地從最新版本Play 2.5.x開始,它使用的是Akka Streams。 – cchantep

+0

使用'Future.successful('而不是'Future(' – rethab

+0

@rethab - 恐怕沒什麼區別:( –

回答

0

我可能是完全錯誤的這一點,但我現在有一個理論,以正在發生的事情.....

如果我使用Action.async,枚舉回調實際上只被計算一次Action塊已經完成,因此stmt和result對象已經完成並且不再有效。另一方面,如果我通過使用等待來阻止Action直到結果可用(我意識到文檔說你不應該這樣做),那麼Action塊的值尚未最終確定,因此我得到了預期結果。

正如我在問題中所說的,我仍然試圖讓我的頭如何Scala和Play的工作,所以如果你知道更好請評論!