2

编辑
开始卡盘(抛出异常),然后没有“坏”数据要缓存。通过捕获异常,甚至包含在 Either[Why-Fail, Option[T]] 中,我只是为自己做更多的工作。异常是(理想情况下)异常,所以记录,抛出,然后继续......

原始
缓存很好,但缓存失败的操作很糟糕

Cache.orElse("directory.active") {
  Ok( dao.findAll(active = true) as json )
}

DAO 数据库查找可能会失败(在这种情况下,数据库/查询失败时会返回一个空列表),这将导致缓存错误数据。

如何解决这个问题?我们只想运行一次查询,然后缓存进一步的请求。在 Scala 中,您可以进行惰性初始化,但这会产生永久缓存,这也是不可取的(需要在成员目录添加/编辑时清除缓存)。

假设这适用于任何平台:基本上需要执行一次操作并将其缓存在成功的结果上

4

2 回答 2

1

我没有方便的缓存实现,所以无法测试这个,但是像这样的东西怎么样:

def getCache[A](key:String, result:()=>A)(invalidTest:A=>Boolean):Option[A] = {
  Cache.get(key).getOrElse {
    result match {
      case m:A if (!invalidTest(m)) => Cache.set(key,m);Some(m)
      case _ => None
    }
  }
}

getCache("directory.active", () => dao.findAll(active = true))(_.isEmpty)

正如您所说,您可以轻松地使用 pimp Cache 来添加它,并对您放入缓存的类型进行默认有效性测试。

如果您想缓存 Action 结果(并且如果您总是返回 json,并且如果as json返回 Json 类型——抱歉,不是 Play 人),也许:

def getCache[A](key:String, result:()=>A)(invalidTest:A=>Boolean):SimpleResult[Json] = {
  Cache.get(key).getOrElse {
    result match {
      case m:A if (!invalidTest(m)) => Cache.set(key,Ok(m as json));Ok(m as json)
      case x:A => Ok(x as json)
      case _ => Ok(errorjson as json)
    }
  }
}

getCache("directory.active", () => dao.findAll(active = true))(_.isEmpty)
于 2012-07-13T22:07:43.200 回答
0

感谢@brandon,我想出了一个对 Play缓存实现的蛋糕和吃它太拉皮条

def orElse[A,B](key: String, expire: Int = 0)
  (canFail: => B)(failOn: B => Boolean)(body: B => A)
  (implicit m: ClassManifest[A]): A = {

  PlayCache.getAs[A](key).getOrElse {
    canFail match {
      case x if(!failOn(x)) => // all good, cache away
        val tmp = body(x); set(key, tmp, expire); tmp
      case x => body(x) // never cache a failure
    }
  }
}

然后像这样使用:

Cache.orElse("directory.active")(dao.findAll(active = true))(_.isEmpty) { 
  model=> Ok( directory.index(model) )
}

这给我们带来的是选择性缓存可能失败的操作的能力,同时保留缓存注入 canFail 操作的 html 包装器的能力。在这种特殊情况下,findAll 查询返回@400 个成员记录并在 html 层生成一个 jQuery DataTable(生成 150KB),因此需要缓存整个操作。

于 2012-07-13T15:55:55.933 回答