-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: No entry in second level cache for one-to-one relationships
PostPosted: Wed May 19, 2010 12:19 pm 
Newbie

Joined: Thu Feb 11, 2010 12:29 pm
Posts: 2
Hi,

I have a series of objects related by one-to-many and one-to-one relationships; here are the configuration relevant parts:

<class name="A" table="A">
<cache usage="read-only"/>
<id name="aId" type="long">
<column name="ID" precision="5" scale="0" not-null="true" />
</id>

<one-to-one name="c" class="C"/>

<set name="bs" lazy="false" fetch="select" inverse="true">
<cache usage="read-only"/>
<key update="false">
<column name="ID" not-null="true"/>
</key>
<one-to-many class="B"/>
</set>
<!-- other properties follow -->
</class>

<class name="C" table="C" dynamic-update="true">
<cache usage="read-only"/>
<id name="id" type="long" unsaved-value="any">
<column name="ID" precision="5" scale="0" not-null="true" />
</id>
<!-- <one-to-one name="a" class="A" constrained="true"/> -->
<!-- other properties follow -->
</class>


<-- not really relevant to the problem but here is anyway -->
<class name="B" table="B">
<cache usage="read-only"/>
<composite-id name="bId" class="BID">
<key-property name="id" type="long" >
<column name="ID" precision="5" scale="0" not-null="true" />
</key-property>
<key-property name="st" type="string">
<column name="ST" length="2" not-null="true"/>
</key-property>
</composite-id>
<many-to-one name="a" column="ID" class="A" insert="false" update="false"/>
<!-- other properties follow -->
</class>

As you can see, second level caching is configured.

Some of the records in table A do not have a record in table C or B. After loading (actually using get()) objects from A (which would fire queries to get B and C as well), these A objects are cached (and also B and C if available). However, if a particular object in A does not have a record in C, when I try to load it again Hibernate will fire another query to the database to try to read C as it cannot find it in the second level cache (because there is actually no record in C); this is causing a performance degradation. This does not happen with objects from collection B (if the first time that A is loaded there are no records in B, then the second time A is loaded Hibernate does not try to read B again from DB).

Looking at the second level cache contents I see objects from A being cached; for the B cache (the collection) there is always an entry with the ID from A and a list associated (which would be empty if there are no B records for that A record); for the C cache, there is an entry only if there is a record in C corresponding to the ID in A. Then if an object from A that doesn't have records in B or C is loaded, there is a hit in the B cache (which will return an empty list and won't go to the DB), however, there will be a miss in the C cache (as there is no entry there for the ID from A, which will cause a trip to the database).

Questions:
1- Is there a way to enforce that one-to-one relationships are cached even though there are no records in one of the sides? E.g. something like for the C cache to have all IDs from A associated to some value that means that is cached but there is no C record.
2- From what I read in the documentation for the collection B defined in A to be cached you have to add <cache /> in the mapping for A, however, I found that unless I add <cache /> also in the mapping for B, the B objects won't be in the second level cache. Is this the way is supposed to be?


Top
 Profile  
 
 Post subject: Re: No entry in second level cache for one-to-one relationships
PostPosted: Thu May 20, 2010 1:06 pm 
Newbie

Joined: Thu Feb 11, 2010 12:29 pm
Posts: 2
Hi,

I looked a little more into the Hibernate code and this is what I have found so far:

1- The following is valid for a load of an object from class A that does not have objects of class B (the collection or set in this case) nor of class C (mapped by a one-to-one relationship).
2- When Hibernate is hydrating object A and arrives to the property that holds a reference to class C:
2a- Tries to resolve this type
2b- Eventually it will run a query (EntityLoader.doQuery()) which will return no data as there is no record in C for this particular ID
2c- Then in Loader.initializeEntitiesAndCollections(), as there won't be any objects to hydrate (properties of class C), it won't call the TwoPhaseLoad.initializeEntity() method for class C. This last method is where objects of class C are usually cached in the C cache, but it will never happen (no entry will be added to the cache) for those records in A that do not have a corresponding record in C.
3- When Hibernate is hydrating object A and arrives to the property that hold a reference to class B:
3a- Will resolve the type (but won't load the collection data yet)
4- After object A is fully hydrated, it will eventually call StatefulPersistenceContext.initializeNonLazyCollections() which at some point will do Loader.endCollectionLoad(), which will call CollectionLoadContext.endLoadingCollections(), which ultimately will call addCollectionToCache(). This last method will add a collection (even an empty one as in the case when there are no records in B) to the B cache.

In the end what happens is that collections are kind-of post processed and initialized after the "parent" object, and during this initialization they are cached (no matter which values - if any - they have). On the other hand, one to one relationships do not have this, and as soon as the "child" record is not there nothing else gets done and no caching is done.

I believe one-to-one relationships should also be cached in the same way as collections are dealt with, that is, even if the "child" (for lacking a better name) is not there, there should still be a cache entry with the ID of the "parent" record.

Does anyone know if I am doing something wrong? Is this the expected behavior or could my suggestion be applied as an enhancement?

Please let me know, this is causing us some performance issues.

Regards,

Cris.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.