查询数据库

时间:2016-09-27 15:22:46

标签: scala playframework

我是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()在两个上下文中表现不同,但我无法弄清楚原因。我想知道是否在并行线程中调用了不同的迭代,但每次运行代码时都会可靠地重现这一点,因此我不认为它是线程并发问题。谢谢你的时间!

1 个答案:

答案 0 :(得分:0)

我可能完全错了,但我现在有一个关于发生了什么的理论......

如果我正在使用Action.async,则只有在Action块完成后才会实际评估枚举器回调,因此stmt和result对象已经完成并且不再有效。另一方面,如果我通过使用Await阻止Action直到结果可用(我意识到文档说你不应该这样做),那么Action块的值还没有最终确定,因此我得到预期的结果。

正如我在问题中所说的那样,我仍然试图了解Scala和Play是如何工作的,所以如果你知道的话请发表评论!