在我的Spring驱动的应用程序中,我使用Hibernate(4.2.15.Final)和EhCache(2.6.9)作为第二级缓存,在标准的持久层中进行了设置。
一切正常。但是,将条目放入第二级缓存有时会花费一些时间。
我已经在一个显式ehcache.xml文件中配置了域模型类的缓存(我没有配置默认缓存):
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。
ObjectGraphWalker
maxBytesLocalHeap
我的领域模型非常复杂,我知道可以通过@IgnoreSizeOf注释限制图表的移动,但是我不确定如何解决该问题:
@IgnoreSizeOf
maxEntriesLocalHeap
[更新]:我发现,Hibernate不会缓存临时成员,所以无论如何ehcache都不应考虑它们。正确?
简短答案
原来,我遇到的问题是由于在模型中使用了Joda- Time实例(我使用Jadira的UserType库来映射Joda类型)。
Joda类型保留了各种内部引用(包括对导致年代久远的对象图的年代信息的引用),而Ehcache遍历SizeOfEngine这些引用导致了我的原始警告。
SizeOfEngine
我没有找到一种干净的方法来配置SizeOfEngine引擎以排除这些引用,但是再一次,我猜想一种更干净的方法是强制Hibernate首先仅将相关信息放入第二级缓存(在我的时间实例中的情况LocalDateTimes)。
LocalDateTimes
更多细节
这是我关于OP的发现(使用Hibernate 4.2.15.Final,EhCache 2.6.9和UserType 3.2.0.GA):
首先,我对Hibernate如何在第二级缓存中存储实体存有误解。阅读Lorimer关于真正了解二级缓存和查询缓存的博客条目后,很多事情对我来说更有意义: