Future 上的 lazy val 是否会阻止实际的数据库调用?

Does lazy val on a Future prevent an actual database call?

我想进行这样的查询:

  1. 查询特定日期的记录;
  2. 如果 (1) 失败,则查询日期范围内的记录,取最后一个日期。

我现在的处理方式是:


lazy val specific: Future[Option[QueryResponse]] = // some database call

lazy val range: Future[Option[QueryResponse]] = 
  // some database call returning Future[Seq[QueryResponse]]
  .map { qrs =>
    if (qrs.nonEmpty) Some(qrs.maxBy(_.date)(_ compareTo _))
    else None
  }

for {
  s <- specific  
  r <- range
} yield {
 (s, r) // match on combination of Some/None
}

两个问题:

  1. 惰性会阻止对数据库调用的评估吗?我希望尽可能少地拨打电话。这与其他任何问题一样都是语言问题。
  2. 认识到无论如何都必须调用 1 次数据库,最好调用一个范围,然后在 POJO 上本地过滤以找到最新日期,对吗?

就目前而言,您的代码将同时执行 specificrange,尽管它们是惰性的。考虑以下简化的片段

  lazy val specific = Future(Some("specific"))
  lazy val range = Future(Some("range"))

  (for {
    s <- specific
    r <- range
  } yield {
    (s, r)
  }).foreach(println)

输出

(Some(specific),Some(range))

我们看到两人都被处决了。 for-comprehension 的性质意味着它们都 运行 尽管被宣布为懒惰。如果您希望 range 仅在 specific returns 没有结果时才执行,那么请考虑这样做

specific.flatMap {
    case Some(v) => Future(Some(v), None)
    case _ => range.map {
      case Some(v) => (None, Some(v))
      case _ => (None, None)
    }
  }.foreach(println)

输出

(Some(specific),None)

我们看到的地方 range 没有 运行.

Scalaz 将问题简化为

import scalaz._
import scalaz.std.scalaFuture.futureInstance

OptionT(specific).orElse(OptionT(range)).map(println)

输出

specific

这意味着 range 没有 运行。