Skip to main content

Hibernate Bites... (revisited)

An update to this post. Okay, so we have been able to make the caching work with very little changes to our mappings. By moving the cache element from the child entity definition into the collection declaration in the parent entity we have gotten the caching to work.


Robert said…
You might find you want both... the reason is that the caches aren't caching what you think.

An entity cache will cache the actual entity, but not the relationships. A collection (or query) cache will cache the relationship, but not the entity. A few examples will help clarify the difference.

You mention a web service that brings back 1000 objects. Let's call that object Foo, and say that each Foo has a collection of Bar.

You run a query that will bring back some Foo instances. The query runs against the database, and Hibernate gets a list of IDs (and other data); these IDs are used to look up the Foo instances in the second-level cache (if needed; Hibernate will happily re-create the instances inf the query has enough data).

So now Hibernate has a collection of Foo instances. But you want the Bar instances for each Foo... and that wasn't in the cache (because the cache stores the entity only). So Hibernate needs to run a query to get the IDs of the Bar instances. Hibernate needs to run this query N times - where N is the number of Foo instances.

You can cache this query by caching the collection - but all that this cache stores are the matched IDs. Hibernate then needs to create the Bar instance, either from the Bar cache, or the query that got the IDs or via another query.

So the result is that you want three caches: a cache on Foo, a cache on Bar, and a cache on the Foo->Bar collection.

But wait... that's not all! Any update to any Bar instance will invalidate the Foo-Bar collection cache. So if Bar is an object that regularly changes, or new Bar instances are regularly created, then the collection cache won't help you out very much in production.

There are two options that may help:

a) make the Foo->Bar collection lazy (only good if you don't need the Bar collection in the web service)

b) have a very large fetch size, so that multiple Bar instances can be brought back at a time (thus reducing the value of N).
In our case, we decided to keep it just at the parent entity cached with the embedded collection cached.
1. All of our Hibernate objects are completely read-only. We control the database and only touch it at release time. This way we can rule out the update/freshness issue.
2. Only the parent entities are directly retrieved. The child entities are never directly fetched.

Popular posts from this blog

Using MonoDevelop to Create an ASP.NET Web Service

NOTE: instructions below are for MonoDevelop 2.6 Beta 2 - built on 2011-04-06 03:37:58+0000Getting StartedCreate a new ASP.NET Web Application in MonoDevelop: From the menu, select: File → New → Solution…Expand C#.Select ASP.NET → Web Application.Enter a name for the ASP.NET project that will be created in the solution in Name:.Change the root location for the solution in Location:, if desired.Change the name of the root solution in Solution Name:, if desired.The Results – IWhat you have after executing the new ASP.NET Web Application project wizard is a solution containing one ASP.NET Web Application project. In the default project view in MonoDevelop, you'll find the following items: Default.aspx – This is the default web form rendered and presented in the browser when http://<server>:<port>/ is accessed. Default.aspx.cs – This C# file contains the developer-created common code and event handlers which can be used to affect the processing of the form.Default.aspx.des…

Testing Toolbelt: SpringJUnit4ClassRunner

The org.springframework.test.context.junit4.SpringJUnit4ClassRunner class is another implementation of the JUnit TestRunner class which is used to enable various features of Spring for every run of the test class and every test within it. To use the features provided by the SpringJUnit4ClassRunner class, you need to mark the class using the RunWith annotation using SpringJUnit4ClassRunner as its parameter.In addition to the custom test runner, you will want to mark the class with the ContextConfiguration annotation. The ContextConfiguration annotation is used to mark classes which will automatically read a Spring configuration file and use it to create an ApplicationContext. By default, this file located at <package path>/<test class name>-context.xml. Use the locations argument to over-ride.The ApplicationContext used by the Spring-integrated test will only be loaded once for the whole test class. This behavior can be over-ridden by annotating a test method with the Dirti…