2016-12-27 98 views
0

我有一个Java/Spring应用程序与数据库实体。 其中一个实体是DataSet。每个DataSet可以有一个父节点DataSet。 并且父母 - DataSet有多个(OneToMany)子女。休眠集合缓存

@OneToMany(fetch=FetchType.LAZY) 
    @IndexColumn(name = "order_id") 
    @JoinColumn(name = "parent_dst_id") 
    @Fetch(FetchMode.SELECT) 
    @Cache(usage = org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE) 
    public List<DataSet> getChildren() 
    { 
     return children; 
    } 

经过几年很多在某些父数据集进行分组的数据集。

parentDataset.getChildren().size() // > 200.000 

在代码(我不知道这是正确的方式)增加一个新的数据集(调查)与母体时,以下行执行:

surveyDataset.setParent(parentDataset); 
parentDataset.getChildren().add(surveyDataset); 

直到最近children根本没有被缓存。第二条语句导致数据库中的长时间运行查询。

现在我们最近添加了datasets.children到缓存。这样,一切都变得非常快。

直到...

..一个孩子,数据集添加(同一母公司下进行!)再次变得很慢(即:它开始再次查询该数据库)。

我认为缓存正在被驱逐或清除或者其他什么,这就是再次查询的原因。

参见:http://planet.jboss.org/post/collection_caching_in_the_hibernate_second_level_cacheTLDR: “Hibernate并不在缓存更新集合,它只是删除它。”)

我试图理解日志(net.sf.ehcache = DEBUG和org.hibernate.SQL = DEBUG)但那很困难。

所以我只能和我有什么做的,以防止再次加载所有儿童的数据集(在新数据集中的所有兄弟姐妹)有几个问题

1)? 2)如何调试我的缓存中发生了什么?它驱逐父母吗?还是所有的孩子?正如文章中所解释的那样,它可能会重新加载整个集合。

回答

0
  1. 您可以将cache usage =“read-write”更改为cache usage =“read-only”,然后在代码中维护驱逐策略。这是管理缓存的最安全方式,但需要在管理缓存的代码中进行相当多的调整。

  2. 调试有2种方法。

    1. 在hibernate中启用show_sql并查看查询是否执行了两次,这通常表明hibernate试图首先检查缓存,找不到并发送第二个查询数据库的方式。
    2. 日志高速缓存命中率在这篇文章中所解释的:http://winterbe.com/posts/2009/10/01/how-to-log-hibernate-cache-this/
+0

谢谢! “维持驱逐政策”究竟意味着什么? – codesmith

+0

当你把缓存用法=“读写”时,hibernate处理对象驱逐。只要使用session.save/update更新任何对象,它就会从缓存中逐出缓存的对象。但是Read不允许hibernate这样做,所以你将不得不以编程方式在代码中写入缓存逐出来处理它。 – user1622369