I am trying out caching in my play app, and it looks like it is working, but the code seems more verbose than I expected, and I'd appreciate any comments on simplification or something that I am missing. This question is a bit of an extension to this basic cache question. The code (slightly simplified for presentation here) is as follows:
def findById(id: Int): Option[Learner] = {
Cache.getAs[Learner]("learner." + id) match {
case None => DB.withConnection { implicit c => //-- no cache, read DB
SQL("select * from learner where id={id}")
.on('id -> id)
.as(learnerP.singleOpt) match {
case Some(learner) => { //-- found, set cache
Cache.set("learner." + learner.id, learner)
Some(learner)
}
case _ => None //-- no find in DB, do not set cache
}
}
case Some(learner) => Some(learner) //-- return value in cache
}
}
Edit: It's important to set the cache values anywhere that Learner (in this case) is updated or inserted. Setting on insert is necessary, otherwise a query prior to the insert will set the cache to None, and then future getAs or getOrElse calls will return None, even though a value now exists.
You could use the getOrElse
method like this:
Cache.getOrElse[Option[Learner]]("learner." + id, expiration_time) {
DB.withConnection { implicit c => //-- no cache, read DB
SQL("select * from learner where id={id}")
.on('id -> id)
.as(learnerP.singleOpt)
}
}
If the Option[Learner]
is found in memory, it is returned immediately, if it isn't, the call to DB is done and the result is cached with an expiration time expiration_time
.