问题描述
在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 |使用代理sizeof引擎
以及执行过程中的以下WARNING
ObjectGraphWalker |在尝试计算对象图的大小时,达到配置的1,000个对象引用的限制。如果上浆操作继续下去,严重的性能可能会降低。 [...]
AFAIK ObjectGraphWalker
必须调整放入缓存的实体的大小,因为我使用 maxBytesLocalHeap
配置了单个缓存区域。
我的域模型非常复杂,我知道我可以用 @IgnoreSizeOf
注释来限制图的走动,但我不确定如何解决问题:
- 我是否必须忽略双向关联的一侧以避免周期? / li>
- 是否必须显式忽略我的域模型类的临时成员?
- 一般来说,使用
maxBytesLocalHeap
与Eibernate一起使用EhCache,还是应该解决maxEntriesLocalHeap
,因为Hibernate为每个实体保留一个单独的缓存区域?
[UPDATE] :我发现,临时成员不会被Hibernate缓存(参见来映射Joda类型)。
Joda类型保留各种内部引用(包括引用大型对象图的年代信息)和Ehcache的 SizeOfEngine $ c $
我发现没有干净的方式来配置SizeOfEngine引擎来排除这些引用,但我再次猜测一个更简洁的方法将迫使Hibernate首先将相关信息放入第二级缓存(在我的情况下,时间实例为 LocalDateTimes
)。
更新
Jadira在实现自定义类型时做出了糟糕的选择:请参阅
更多详细信息
这是我发现的有关我的OP(使用Hibernate 4.2.15.Final, EhCache 2.6 .9和UserType 3.2.0.GA):
首先,我对Hibernate是如何将实体存储在二级缓存中存在误解。在阅读Lorimer关于的博客文章后,对我来说更有意义:
- 您不必担心双向关联(或循环图表),因为Hibernate只会将关联的ID放入缓存中。即使将整个实体引用到缓存中 - 它不会 - EhCache的SizeOf引擎将跟踪已访问的图中的对象,并且不会将它们的大小设置为两次。
- 同样,您不必担心瞬态字段,因为Hibernate不会将它们放入缓存中。
- 理论上应该没有任何问题出现在
maxBytesLocalHeap
配置。当您使用由EhCache的SizeOf引擎无法正确测量的自定义用户类型时,目前会出现问题。
I have a pretty standard persistence layer setup in my Spring driven application using Hibernate (4.2.15.Final) with EhCache (2.6.9) as 2nd level cache.
Everything works as expected. However, putting entries into the 2nd level cache sometimes takes ages.
I've configured caching of my domain model classes in an explicit ehcache.xml
file (I didn't configure a default cache):
<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>
I get the following INFO message logged at startup of the persistence context:
DefaultSizeOfEngine | using Agent sizeof engine
and the following WARNING during execution
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 the ObjectGraphWalker
has to size the entities that are put into the cache, because I configured the single cache regions with maxBytesLocalHeap
.
My domain model is quite complex and I know that I can limit the walking of the graph with @IgnoreSizeOf
annotations, but I'm uncertain how to tackle the problem:
- Do I have to ignore one side of a bidirectional association to avoid cycles?
- Do I have to explicitly ignore transient members of my domain model classes?
- In general, is it wise to go with
maxBytesLocalHeap
when using EhCache together with Hibernate or should I settle formaxEntriesLocalHeap
, because Hibernate is keeping a separate cache region for each entity anyway?
[UPDATE]: I discovered, that transient members will not be cached by Hibernate (see Hibernate: Is it possible to save a transient field in second level cache?), so they should not be regarded by ehcache anyway. Correct?
Short answer
Turns out that the problem I'm having is a result of using Joda-Time instances in my model (I'm using Jadira's UserType library to map Joda types).
Joda types keep all sorts of internal references (including references to chronology information resulting in a huge object graph) and Ehcache's SizeOfEngine
walks these references leading to my original warning.
I found no clean way how to configure the SizeOfEngine engine to exclude these references, but then again I guess a cleaner approach would be to force Hibernate to only put the relevant info into the 2nd level cache in the first place (a time instance in my case of LocalDateTimes
).
Update
Jadira took a poor choice when implementing its custom types: See my answer here
More Details
Here's what I found regarding my OP (using Hibernate 4.2.15.Final, EhCache 2.6.9 and UserType 3.2.0.GA):
First of all, I had a misconception about how Hibernate stores entities in it's 2nd-Level cache. After reading Lorimer's blog entry about Truly Understanding the Second-Level and Query Caches a lot of things made more sense to me:
- You don't have to worry about bidirectional associations (or cyclic graphs for that matter), because Hibernate will only put IDs for your associations into the cache. And even if it would put a reference to the whole entity into the cache - which it doesn't - EhCache's SizeOf Engine would track objects in the graph already visited and would not size them twice.
- Again, you don't have to worry about transient fields, because Hibernate will not put them into the cache
- In theory there shouldn't be any problem going with a
maxBytesLocalHeap
configuration. Currently problems arise when you use custom user types which are not measured correctly by EhCache's SizeOf engine.
这篇关于EhCache Hibernate第二级缓存maxBytesLocalHeap缓慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!