我在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 < code > ObjectGraphWalker 必须确定放入缓存的实体的大小,因为我用< code>maxBytesLocalHeap配置了单个缓存区域。
我的域模型相当复杂,我知道我可以使用@IgnoreSizeOf
注释限制图的行走,但我不确定如何解决这个问题:
maxBytesLocalHeap
是明智的,还是应该满足于maxEntriesLocalHeap
,因为Hibernate无论如何都为每个实体保留了一个单独的缓存区域? [更新]:我发现,Hibernate不会缓存临时成员(请参阅Hibernate:是否可以在二级缓存中保存临时字段?),因此,ehcache无论如何都不应将其视为一种工具。对的
我知道这是一个老问题。但它可能对某人有用。我也有同样的警告。我花了很多时间来解决这个问题。在我的例子中,EhCache不会忽略所有Hibernate代理类。我的实体有一些具有惰性关联的字段,并且在测量大小期间,EhCache遍历整个Hibernate图。
最后我找到了这个页面并解决了它。
简短回答
事实证明,我遇到的问题是在我的模型中使用Joda-Time实例的结果(我使用Jadira的UserType库来映射Joda类型)。
Joda类型保存各种内部引用(包括对导致巨大对象图的时序信息的引用), Ehcache的< code>SizeOfEngine遍历这些引用,导致我最初的警告。
我发现没有干净的方法来配置SizeOfEngine引擎以排除这些引用,但我想更干净的方法是强制Hibernate首先将相关信息放入第2级缓存中(在我的情况下是时间实例LocalDateTimes
)。
使现代化
Jadira在实现它的自定义类型时做了一个糟糕的选择:请看我的回答
更多详情
以下是我发现的关于我的OP(使用Hibernate 4.2.15.Final,EhCache 2.6.9和UserType 3.2.0.GA):
首先,我对Hibernate如何将实体存储在其2级缓存中有一个误解。在阅读了Lormer关于真正理解二级缓存和查询缓存的博客条目后,很多事情对我来说更有意义: