休眠Grails应用程序中的第二级缓存 [英] Hibernate 2nd level cache in a Grails app

查看:136
本文介绍了休眠Grails应用程序中的第二级缓存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

第一部分



在Grails应用程序中,我明白您可以通过添加
$ b $来为每个域类启用第二级缓存b

 静态映射{
cache true
}

默认情况下,仅在调用 get()时使用二级缓存,但它也可以用于条件查询和动态查找器,方法是将缓存真正到查询。



然而,我仍然不确定我了解查询缓存的工作原理。我最好的猜测是:


  • 每个域类都有单独的查询缓存,例如,在像 Author.findByName('bob',[cache:true])之类的查询之前,为Book和另一个作者

  • 执行,计算基于域类(Author),查询(findByName)和查询参数('bob')的缓存键。如果在作者查询缓存中找到该关键字,则每当作者被保存,删除或更新时,都会返回缓存结果而不是执行查询

  • ,作者查询缓存刷新



直到我们认为返回Book实例的查询可能会加入到Author表中,这似乎是合理的。在这种情况下,当作者被保存,删除或更新时,需要刷新Book和Author查询缓存。这让我怀疑,也许只有一个查询缓存,并且只要保存了任何缓存的域类,它就会被清除?

第二部分



在Grails文档中,它提到了


除了可以使用Hibernate的二级缓存来缓存实例还可以缓存对象的集合(关联)。


例如:

  class Author [

static hasMany = [books:Book]

static mapping = {
cache true //作者使用二级缓存
books cache:true //关联书籍使用第二级缓存


$ b $ class book {
static belongsTo = [author:Author]

static mapping = {
cache true // Book使用第二级缓存
}
}

上面的配置是否有意义,例如,如果Author和Book本身使用二级缓存,那么使Author-book协会也使用二级缓存有什么好处?



第三部分



最后,我读过,这表明它只应用于不常更改的域类。有没有什么情况下不应该为 get()操作启用第二级缓存,也就是说为什么不将以下内容添加到域类中? p>

  static mapping = {
cache true // Book使用二级缓存
}


第1部分:

< Hibernate做正确的事情。查询缓存不是每个实体。有一个查询缓存区域,由所有查询共享,除非您为查询设置了特定区域。每次更新表时,其时间戳高速缓存中的时间戳都会更新。每次执行查询时,将查询搜索的每个表的时间戳与缓存结果的时间戳进行比较。当然,只有当itstimestamp比所有表格时间戳更新时,才会返回缓存结果。



第2部分:

是的,这很有道理。作者的缓存记住ID为456的作者的名称为foo,出生日期为1975/07/19。只有存储在作者表中的数据被记住。因此,缓存关联也是有用的:在调用 author.getBooks()时,不用额外的查询来获取作者的书集,Hibernate将获得ID作者书籍从它的缓存中读取,然后从第二级缓存中加载每本书。不过,请确保缓存图书。



第3部分:

我可以想象几个理由:


  • 有很多实体,它们如此改变,以至于缓存命中的数量会非常低,而且二级缓存处理实际上会消耗更多的时间和内存。没有缓存的解决方案
  • 应用程序是集群化的,分布式二级缓存的成本和复杂性过高,收益较低

  • 其他非Hibernate应用程序写入同一个数据库,因此缓存会返回过时的数据,这是不可接受的

  • 如果没有二级缓存,一切都会很顺利,并且没有理由让应用程序比它更复杂。


Part I

In a Grails app, I understand that you enable the 2nd level cache per domain class by adding

static mapping {
  cache true
}

By default the 2nd level cache is only used when get() is called, but it can also be used for criteria queries and dynamic finders by adding cache true to the query.

However, I'm still not sure I understand how the query cache works. My best guess is that:

  • there are separate query caches for each domain class, e.g. one for Book and another for Author
  • before a query like Author.findByName('bob', [cache: true]) is executed, a cache key is computed, which is based on the domain class (Author), the query (findByName) and the query parameters ('bob'). If that key is found in the Author query cache, the cached results are returned instead of executing the query
  • any time an Author is saved, deleted, or updated, the Author query cache is flushed

This seems reasonable until we consider that a query that returns Book instances may join to the Author table. In that case, it would be necessary to flush both the Book and Author query caches when an Author is saved, deleted, or updated. This leads me to suspect that perhaps there is just one single query cache and it is cleared whenever any cached domain class is saved?

Part II

In the Grails docs it mentions that

As well as the ability to use Hibernate's second level cache to cache instances you can also cache collections (associations) of objects.

For example:

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
  }
}

Does the configuration above make sense, i.e. if Author and Book are themselves using the 2nd level cache, is there any benefit to making the Author-Book association also use the 2nd level cache?

Part III

Finally, I've read this advice about using the 2nd level query cache, which suggests that it should only be used for infrequently changing domain classes. Are there any circumstances under which one should not enable the 2nd level cache for get() operations, i.e. any reason why one wouldn't add the following to a domain class

static mapping = {
  cache true // Book uses the 2nd level cache
}

解决方案

Part 1:

Hibernate does the right thing. The query cache is not per entity. There is a single query cache region, shared by all queries, unless you set a specific region for a query. Each time a table is updated, its timestamp in the timestamps cache is updated. Each time a query is executed, the timestamp of each of the tables where the query searches is compared to the timestamp of the cached result. And of course, the cached result is returned only if itstimestamp is more recent than all the table timestamps.

Part 2:

Yes, it makes sense. The cache for the author remembers that the author with ID 456 has the name "foo" and the birth date 1975/07/19. Only the data stored in the author table is remembered. So, caching the association is also useful: instead of making an additional query to get the set of books of the author when calling author.getBooks(), Hibernate will get the IDs of the books of the author from its cache, and then load each book from the second-level cache. Make sure to cache the Books, though.

Part 3:

I can imagine several reasons:

  • there are so many entities and they are so changing that the number of cache hits would be very low, and that the second-level cache handling would in fact consume more time and memory than a solution without cache
  • the application is clustered, and the cost and complexity of a distributed second-level cache is too high, for a low gain
  • other non-hibernate applications write to the same database, and the cache has thus a big risk of returning stale data, which is not acceptable
  • everything goes very well without a second-level cache, and there is no reason to make the application more complex than it is.

这篇关于休眠Grails应用程序中的第二级缓存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆