在Grails应用程序中,我了解您通过添加
为每个域类启用第二级缓存static mapping {
cache true
}
默认情况下,第二级缓存仅在调用get()
时使用,但也可以通过向查询添加cache true
来用于条件查询和动态查找器。
但是,我仍然不确定我是否了解查询缓存的工作原理。我最好的猜测是:
Author.findByName('bob', [cache: true])
之类的查询之前,计算缓存键,该缓存键基于域类(作者),查询(findByName)和查询参数('bob')。如果在Author查询缓存中找到该密钥,则返回缓存的结果,而不是执行查询在我们考虑返回Book实例的查询可以加入Author表之前,这似乎是合理的。在这种情况下,在保存,删除或更新作者时,有必要刷新Book和Author查询缓存。这让我怀疑可能只有一个查询缓存,只要保存了任何缓存的域类,它就会被清除?
在Grails文档中,它提到了
除了能够使用Hibernate的二级缓存来缓存实例之外,您还可以缓存对象的集合(关联)。
例如:
class Author {
static hasMany = [books: Book]
static mapping = {
cache true // Author uses the 2nd level cache
books cache: true // associated books use the 2nd level cache
}
}
class Book {
static belongsTo = [author: Author]
static mapping = {
cache true // Book uses the 2nd level cache
}
}
上面的配置是否有意义,即如果Author和Book本身使用二级缓存,那么使Author-Book关联也使用二级缓存有什么好处吗?
最后,我读过有关使用二级查询缓存的this advice,这表明它只应用于不经常更改的域类。是否存在不应为get()
操作启用二级缓存的任何情况,即无法将以下内容添加到域类的任何原因
static mapping = {
cache true // Book uses the 2nd level cache
}
答案 0 :(得分:43)
第1部分:
Hibernate做对了。查询缓存不是每个实体。除非您为查询设置特定区域,否则所有查询都会共享一个查询缓存区域。每次更新表时,都会更新时间戳缓存中的时间戳。每次执行查询时,将查询搜索的每个表的时间戳与缓存结果的时间戳进行比较。当然,只有当itstimestamp比所有表时间戳更新时,才会返回缓存的结果。
第2部分:
是的,这很有道理。作者的缓存会记住ID为456的作者名称为“foo”,出生日期为1975/07/19。仅记住存储在作者表中的数据。因此,缓存关联也很有用:在调用author.getBooks()
时,Hibernate将获取作者的书籍ID而不是进行额外的查询,而是从缓存中获取作者的书籍ID,然后加载每本书来自二级缓存。但请确保缓存书籍。
第3部分:
我可以想象几个原因: