修改
开始chucking(抛出异常),然后就没有“坏”数据要缓存。通过捕获异常,甚至包含在Either [Why-Fail,Option [T]]中,我只为自己做了更多工作。例外情况(理想情况下)是例外的,因此记录,抛出和继续......
ORIGINAL
缓存很好,但缓存失败的操作很糟糕
Cache.orElse("directory.active") {
Ok( dao.findAll(active = true) as json )
}
DAO数据库查找可能失败(在这种情况下,在数据库/查询失败时返回空List),这将导致缓存错误数据。
如何解决这个问题?我们只想运行一次查询,然后缓存以进一步请求。在Scala中你可以进行延迟初始化,但这会产生永久缓存,这也是不可取的(需要清除成员目录添加/编辑时的缓存)。
假设这适用于任何平台:基本上需要执行一次操作并将其缓存到成功的结果。
答案 0 :(得分:1)
我没有方便的Cache实现,所以无法测试这个,但是如何:
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)
答案 1 :(得分:0)
感谢@brandon我想出了一个蛋糕吃得太多的Play's Cache implementation
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),因此需要缓存整个操作。