EhCache Hibernate二级缓存maxBytesLocalHeap缓慢

时间:2014-09-16 13:21:49

标签: java hibernate caching jpa ehcache

我在Spring驱动的应用程序中使用Hibernate(4.2.15.Final)和EhCache(2.6.9)作为二级缓存设置了一个非常标准的持久层设置。

一切都按预期工作。但是,将条目放入二级缓存有时需要很长时间。

我已在明确的ehcache.xml文件中配置了我的域模型类的缓存(我没有配置默认缓存):

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         name="hibernate"
         updateCheck="false" 
         monitoring="autodetect"
         dynamicConfig="false"
         maxBytesLocalHeap="300M"
         maxBytesLocalDisk="500M">

   <cache
    name="org.mycorp.model.MyEntity" 
    eternal="true"
    overflowToDisk="false"
    diskPersistent="false"
    maxBytesLocalHeap="5M" />

   ...

</ehcache>

我在启动持久化上下文时记录了以下INFO消息:

DefaultSizeOfEngine | using Agent sizeof engine

以及执行期间的以下警告

ObjectGraphWalker | The configured limit of 1,000 object references was reached while attempting to calculate the size of the object graph. Severe performance degradation could occur if the sizing operation continues. [...]

AFAIK ObjectGraphWalker必须调整放入缓存的实体的大小,因为我使用maxBytesLocalHeap配置了单个缓存区域。

我的域模型非常复杂,我知道我可以使用@IgnoreSizeOf注释来限制图形的行走,但我不确定如何解决这个问题:

  • 我是否必须忽略双向关联的一方以避免循环?
  • 我是否必须明确忽略我的域模型类的瞬态成员?
  • 一般来说,在将Hhnate与EhCache一起使用时使用maxBytesLocalHeap是否明智,或者我应该选择maxEntriesLocalHeap,因为Hibernate无论如何都要为每个实体保留一个单独的缓存区域?

[更新] :我发现,Hibernate不会缓存瞬态成员(请参阅Hibernate: Is it possible to save a transient field in second level cache?),因此无论如何都不应该将它们视为ehcache。正确?

2 个答案:

答案 0 :(得分:3)

简短回答

事实证明,我遇到的问题是在我的模型中使用Joda-Time实例的结果(我使用Jadira's UserType library来映射Joda类型)。

Joda类型保留了各种内部引用(包括对时间顺序信息的引用,从而产生了一个巨大的对象图),Ehcache的SizeOfEngine遍历这些引用,导致我的原始警告。

我发现如何配置SizeOfEngine引擎以排除这些引用没有干净的方法,但是我想再一个更简洁的方法是强制Hibernate只将相关信息放入二级缓存中(一次)在LocalDateTimes}的情况下的实例。

<强>更新

Jadira在实施自定义类型时选择不当:请参阅my answer here

更多详情

以下是我发现的OP(使用Hibernate 4.2.15.Final,EhCache 2.6.9和UserType 3.2.0.GA):

首先,我对Hibernate如何将实体存储在其二级缓存中存在误解。在阅读Lorimer关于Truly Understanding the Second-Level and Query Caches的博客文章之后,很多事情对我来说更有意义:

  • 您不必担心双向关联(或者关于此问题的循环图),因为Hibernate只会将您的关联ID放入缓存中。即使它将整个实体引用到缓存中 - 它也不会--EhCache的SizeOf引擎会跟踪已经访问过的图形中的对象,并且不会对它们进行两次调整。
  • 同样,你不必担心瞬态字段,因为Hibernate不会将它们放入缓存中
  • 理论上,maxBytesLocalHeap配置不应该出现任何问题。当您使用EhCache的SizeOf引擎无法正确测量的自定义用户类型时,会出现问题。

答案 1 :(得分:1)

我知道这是一个老问题。但它可能对某些人有用。 我有同样的警告。我花了很多时间来解决这个问题。 在我的例子中,EhCache不会忽略所有的hibernate代理类。我的实体有一些具有惰性关联的字段,在测量大小期间,EhCache遍历整个休眠图。

最后我找到了this page并解决了它。