查询数据库时奇怪的枚举器/迭代器/未来行为 [英] Strange enumerator/iteratee/Future behaviour when querying database

查看:64
本文介绍了查询数据库时奇怪的枚举器/迭代器/未来行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Scala and Play的新手!编程,但在Django中拥有相当丰富的Web应用程序经验,并且具有大量常规编程经验.

I am new to Scala and Play! programming but have a reasonable amount of experience with webapps in Django, and plenty of general programming experience.

我一直在做一些练习,以提高我对Play的理解!而这种行为使我完全陷入了困境.这是对以下一般问题的后续问题:试图了解Scala枚举器/重复

I have been doing some exercises of my own to try to improve my understanding of Play! and this behaviour has me totally stumped. This is a follow-up question to the more general one here: Trying to understand Scala enumerator/iteratees

我正在尝试使用枚举器,迭代器和期货查询数据库.

I am trying to query a database, using Enumerators, Iteratees and Futures.

当我这样编码控制器时:

When I code my controller thus:

  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))

    }
  }

我在日志中得到了预期的结果:

I get the expected result in the log:

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对象(具有在控制器类中定义的隐式转换器,此处未显示).

and I get the expected JSON object (with an implicit converter defined in the controller class, not shown here).

但是,当我尝试使用Action.async对其进行正确编码时:

However, when I try to code it properly, using 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)}

    }
  }

然后枚举器在第一次运行时终止!

then the enumerator terminates on the first run!

[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数组

and I get a blank JSON array returned

在两种情况下,result.next()的表现似乎有所不同,但我不知道为什么.我想知道是否在并行线程中调用了不同的迭代,但是每次运行代码时都可靠地重现了这一点,因此我不希望它成为线程并发问题.感谢您的宝贵时间!

It appears that result.next() is behaving differently in the two contexts, but I can't work out why. I was wondering whether different iterations are being called in parallel threads, but this is reproduced reliably every time I run the code so I would not expect it to be a thread concurrency issue. Thanks for your time!

推荐答案

我对此可能完全错了,但是我现在对发生的事情有一个理论.....

I may be completely wrong about this, but I now have a theory as to what is going on.....

如果我使用的是Action.async,则仅在Action块完成后才对枚举器回调进行实际评估,因此stmt和result对象已完成,并且不再起作用.另一方面,如果我通过使用Await阻止Action直到结果可用(我意识到文档中说您不应该这样做),则Action块的值尚未最终确定,因此我得到了预期结果.

If I am using Action.async, the enumerator callbacks are only actually being evaluated once the Action block has finished and therefore the stmt and result objects have been finalised and no longer work. On the other hand, if I block the Action until the result is available (which I realise that the documentation says you shouldn't do) by using Await, then the values with the Action block have not yet been finalised and therefore I get the expected result.

正如我在问题中所说,我仍在努力了解Scala和Play的工作原理,因此,如果您更好地了解,请发表评论!

As I said in the question, I am still trying to get my head around how Scala and Play work so if you know better please comment!

这篇关于查询数据库时奇怪的枚举器/迭代器/未来行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆