Understanding SecondLevelCache

15 views
Skip to first unread message

eigeneachse

unread,
Nov 13, 2009, 4:14:13 PM11/13/09
to nhusers
Hi@all,
i have read various posts, blogs.... about the nhibernate caching
methods. For me it is good that my SysCache2 configuration is working.
But it is only working in parts and i have a few problems in my
understanding if this is an configuration failure on my side or if
there is something other wrong.

So i have the following HQL Query

return Session.CreateQuery(@"
select something.....")
.SetParameter(0, aParameter)
.SetParameter(1, aSecondParameter)
.SetCacheable(true)
.SetCacheRegion("10Minutes")
.List<aClass>()[0];

The returning class itself has some references to other tables which
are configured via an one-to-many relationship. When i call this query
then the first time the sql is fired against the database. So the base
objects and the referenced objects are fetched from the database. If i
do this a second time, then only the referenced objects are fetched
over sql again. But why? I think i have configured that everything
should be cached.
And here is where my understanding in nhibernate caching ends. Are
only the base objects cached? Why arent the referenced objects cached?
I read about the query cache and the entity cache. I think that here
the query cache is used. How can the referenced objects be cached?

It would be very good if someone could help my with this. I am really
optimistic that this problem is solved already.
Please let me know if you need more informations.

Thanks in advance for your help

Regards

eigeneachse

Anne Epstein

unread,
Nov 13, 2009, 11:12:36 PM11/13/09
to nhu...@googlegroups.com
Hi! Caching is a bit more difficult to get right than it seems initially.  All entities you want cached should have the cache tag on them, and this includes your referenced object mappings.  If you mark the entity you're referencing as cached, then you should be set for your many-to-one relationships, i.e. . If your query was for Dog and Dog has one Owner(type Person) you would need to set the type Person to be cached to not get the db hit when you traverse the dog-owner relationship. The reason you need to cache Person is because cached Dog only has the OwnerId in it, not a whole Person. NH will index objects of type Person by that ID so if you have Person cached NH will grab it there instead of going to the DB.

Traversing collections off your cached object is similar, but is a bit more involved. Let's say your Dog had a collection of Puppies.  Sure, you may have all Dog objects caching, but when it you have NH cache a Dog, it only caches the things that are in that DB row.  if you think about how collections are implemented in a database, the relationship to Dog isn't in that Dog row, it's in the rows of each of the Puppies as a foreign key so it's not cached with Dog.  Even if each of the puppies is cached, it's that relationship FROM Dog TO the puppies that you need, and will get the query hit for.  Don't want that DB hit?  there's an easy fix:  put a cache tag *inside your collection definitions*, i.e. your lists, sets, bags.  That will cache the *list of ids* of the puppies that Dog has.  Your puppy objects themselve are already cached, right? So now it's like the Dog to Owner: cached id to object, no db hit.

Hope that helps,
Anne

eigeneachse

unread,
Nov 14, 2009, 4:17:44 PM11/14/09
to nhusers
Hi Anne,
thank you very much for the reply. I tried to follow your suggestions,
but my collections are not yet fetched from the SL Cache. So here is
what my structure looks like.

ClassA -> Decorated with [Cache(Usage = CacheUsage.ReadWrite, Region =
"10Minutes")]
|_______> SubclassB -> Decorated with [Cache(Usage =
CacheUsage.ReadWrite, Region = "10Minutes")]
|_____________SubclassC -> Decorated with [Cache
(Usage = CacheUsage.ReadWrite, Region = "10Minutes")]
|_____________SubclassD -> Decorated with [Cache
(Usage = CacheUsage.ReadWrite, Region = "10Minutes")]

So first of all, my classes are all decorated with the Cache Tag. Now
i have in my ClassA a OneToMany reference to SubclassB. This reference
is configured as follows

[Bag(0, Lazy = true, Name = "SubclassB ", Cascade = "all", Fetch =
CollectionFetchMode.Unspecified)]
[Key(1, Column = "CLASSA_ID")]
[OneToMany(2, ClassType = typeof(SubclassB))]
[Cache(3, Region = "5Minutes", Usage = CacheUsage.ReadWrite)]
public virtual PersistentGenericBag<SubclassB> SubclassBList{ get;
set; }

I hope this is correct. Now in SubclassB there are to more references.
To SubclassC and SubclassD. Both are ManyToOne references. I will show
you the configs.

[ManyToOne(0, Name = "SubclassC", ClassType = typeof(SubclassC),
Column = "SUBCLASSC_ID", Cascade = "all", Fetch =
FetchMode.Unspecified)]
[Cache(1, Region = "5Minutes", Usage = CacheUsage.ReadWrite)]
public virtual SubclassC SubclassC{ get; set; }


[ManyToOne(0, Name = "SubclassD", ClassType = typeof(SubclassD),
Column = "SUBCLASSC_ID", Cascade = "all", Fetch =
FetchMode.Unspecified)]
[Cache(1, Region = "5Minutes", Usage = CacheUsage.ReadWrite)]
public virtual SubclassD SubclassD{ get; set; }

Ok now i think every class an every collection is configured for
caching. But i have already hits to the db and i do not understand why
i have these hits. What am i doing wrong? Do you have any more hints
for me?

Here is what i found in the nhibernate debug log. It firsts looks for
a cached collection of classA. An surprisingly i get an:

ReadOnlyCache ThreadID=8: Cache hit

This is what i see in my sql profiler. There is no second dbhit for
class a. Alright.
Now he is looking for a cached collection for SubclassB. The result
is:

DefaultInitializeCollectionEventListener ThreadID=8: collection not
cached

And here is what i see in my sql profiler. I get the dbhit. Why? For
SubclassC and D its the same behaviour.

Anne you, and maybe an other professional, are my last hope to get an
success story out of this. Please let my know if you have any other
hints for me.

Thanks in advance

Regards

eigeneachse

Anne Epstein

unread,
Nov 15, 2009, 12:29:53 PM11/15/09
to nhu...@googlegroups.com
Hmm. Just want be sure you're expecting caching to happen on the second time you access each of these structures, correct?  I see you mention that for ClassA, but just like accessing ClassA, you won't get the collections and such that are children of ClassA (or the subclasses ClassB, etc) from the cache until you've retrieved those things once  and taken the first hit on retreival... it doesn't get those things all at once when you retreive ClassA, even though you have a cache it still gets them and puts them into the cache lazily as you access your objects.

Note that you CAN get ClassA's children at the same time as you retreive ClassA, etc by setting the fetchmode to eager... if you always use ClassA's children with ClassA, this could be a good idea, one big db hit instead of a ton of small hits.

Another thing - are any of these classes mapped with composite keys?  Such classes can be set up to cache, but making sure it happens correctly is more involved than just putting on the cache tag.

eigeneachse

unread,
Nov 16, 2009, 2:55:34 AM11/16/09
to nhusers
Hi Anne,
no the classes are only mapped without composite keys. I think here is
no problem.
Regarding the lazy loading problem. I will try to use Eager Fetching
later, but for now i have no lazy loading activated.
But i found out something else.
My whole project is an spring, nhibernate webservice application. I
want to return an xml structure from my ClassA with all the children
over the webservice. When i debug in my DAO class an make something
like

ClassA s = Session.CreateQuery(@"
some query statements
")
.SetParameter(0, aParameter)
.SetParameter(1, aSecondParam)
.SetCacheable(true)
.SetCacheRegion("10Minutes")
.List<ClassA>()[0];

IList<SubclassB> sl = s.SubclassBList;

then i found out that when i first load my ClassA then everything is
ok. When i load the SubclassB list, then the cache is hitten.
Wonderful. ( The genereation of the second list is only for testing
purposes) But now when the gernerated ClassA object is passed through
my hierarchy ( dao -> service -> webservice) then somewhere in the
spring framework there is an additional call to load the children of
ClassA and there is the second db hit again. I did not manually force
the dao to load the subclasses in any of the above hierarchies.

So i am at one point where i think its getting really hard to find out
why the second dbhit is used.
Do you have any ideas regarding this?

Thank you for your help.

Regards

eigeneachse

On Nov 15, 6:29 pm, Anne Epstein <aje...@gmail.com> wrote:
> Hmm. Just want be sure you're expecting caching to happen on the second time
> you access each of these structures, correct?  I see you mention that for
> ClassA, but just like accessing ClassA, you won't get the collections and
> such that are children of ClassA (or the subclasses ClassB, etc) from the
> cache until you've retrieved those things once  and taken the first hit on
> retreival... it doesn't get those things all at once when you retreive
> ClassA, even though you have a cache it still gets them and puts them into
> the cache lazily as you access your objects.
>
> Note that you CAN get ClassA's children at the same time as you retreive
> ClassA, etc by setting the fetchmode to eager... if you always use ClassA's
> children with ClassA, this could be a good idea, one big db hit instead of a
> ton of small hits.
>
> Another thing - are any of these classes mapped with composite keys?  Such
> classes can be set up to cache, but making sure it happens correctly is more
> involved than just putting on the cache tag.
>

eigeneachse

unread,
Nov 16, 2009, 6:04:58 AM11/16/09
to nhusers
Hi Anne,
please forget the previous post. I have some new informations ( I hope
so becaus now i'm a bit confused ).
As i can see in the debuglog of nhibernate, then all entities that are
concerned with the ClassA are in my second level cache. But, and thats
the point, the collection fo my SubclassB is not cached. I think that
there should be a list of ids in my cache that holds the relationship.
An this is not happening.

2009-11-16 11:45:47,584 DEBUG DefaultInitializeCollectionEventListener
ThreadID=8: initializing collection [ClassA.SubclassB#107461023]
2009-11-16 11:45:47,584 DEBUG DefaultInitializeCollectionEventListener
ThreadID=8: checking second-level cache
2009-11-16 11:45:47,584 DEBUG DefaultInitializeCollectionEventListener
ThreadID=8: collection not cached

Is there a flag to set, that these collections should be cached like
cache.use_query_cache or so?

Thank you for your patience.

Regards

eigeneachse

eigeneachse

unread,
Nov 16, 2009, 6:49:45 AM11/16/09
to nhusers
So this is my last post about this ( I hope so ). I got it.
I did not notice that the order of the mapping attributes is
important. I found this here
http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/11/09/first-and-second-level-caching-in-nhibernate.aspx
.

I changed the configuration for my SubclassB Collection to


[Bag(0, Lazy = false, Name = "SubclassBList", Cascade = "all", Fetch =
CollectionFetchMode.Unspecified)]
[Cache(1, Region = "5Minutes", Usage = CacheUsage.ReadWrite)]
[Key(2, Column = "SubclassBList_ID")]
[OneToMany(3, ClassType = typeof(SubclassB))]

and i finally have no unessecary roundtrips to the db.

Anne thank you for your patience..

Regards

eigeneachse
> ...
>
> read more »

Anne Epstein

unread,
Nov 16, 2009, 10:35:53 AM11/16/09
to nhu...@googlegroups.com
No problem, I'm glad you got your problem straightened out! 

I will mention, just because if I don't someone else will probably mention it, that if you have webservices sending large amounts of data back and forth, especially *if* that's happening a lot, your bottleneck may not be a few extra db calls, and you may not see much effect on your application with all this caching work you're putting in-for instance, depending on your situation, you may see a much, much bigger payoff by caching on the client end of the webservice, saving you both the db calls and the ws call most of the time. Anyway, this might not apply to your situation, but if it does, it might be worth considering.

Good luck!
Anne

eigeneachse

unread,
Nov 16, 2009, 3:54:59 PM11/16/09
to nhusers
Hi Anne,
i totally agree with you. Client caching is also very effective. But
this is not in my hands and so i have to do everything that the
serverside is caching enough.

Regards

eigenechse

On Nov 16, 4:35 pm, Anne Epstein <aje...@gmail.com> wrote:
> No problem, I'm glad you got your problem straightened out!
>
> I will mention, just because if I don't someone else will probably mention
> it, that if you have webservices sending large amounts of data back and
> forth, especially *if* that's happening a lot, your bottleneck may not be a
> few extra db calls, and you may not see much effect on your application with
> all this caching work you're putting in-for instance, depending on your
> situation, you may see a much, much bigger payoff by caching on the client
> end of the webservice, saving you both the db calls and the ws call most of
> the time. Anyway, this might not apply to your situation, but if it does, it
> might be worth considering.
>
> Good luck!
> Anne
>
> On Mon, Nov 16, 2009 at 5:49 AM, eigeneachse <eigeneac...@googlemail.com>wrote:
>
>
>
> > So this is my last post about this ( I hope so ). I got it.
> > I did not notice that the order of the mapping attributes is
> > important. I found this here
>
> >http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/11/09/firs...
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages