A couple Hibernate hints
Tuesday, May 6. 2008
Here are a couple things I just learned about Hibernate.
1. HibernateProxy.getHibernateLazyInitializer.getImplementation
Cast your objects as this proxy to find the expected class of your objects at runtime. I know it is not elegant but I have found myself in need of this information more than once.
You have probably seen the proxy classes; they look something like this:
my.Person$$EnhancerByCGLIB$$114dd646
when what you really want is simply this:
my.Person
2. @BatchSize(size = 100) instead of @Fetch(FetchMode.SUBSELECT)
The problem with FetchMode.SUBSELECT is that Hibernate blindly retrieves all the rows in the collection table, regardless of the size of the page set. BatchSize does not retrieve everything all at once, rather it optimizes the number of queries run when OneToMany collections are loaded for lists of objects. Note that the use-case case for this is one in which the collection of child objects must be loaded right away.
This also prevents the infamous n+1 dilemma encountered when no fetch strategy is specified.
For example, lets say you have Persons (parent) who own Cats (children) and you must list 10 Persons on the page along with the number of Cats owned by each Person. (person.cats.size) Of course you could just bite the bullet and let Hibernate run the 11 queries, that is not a problem. But what if you must list 500 Persons on the page? You don't want to run 500 queries. And you don't want to retrieve all the Cats in the Cat table, which is what happens with the FetchMode.SUBSELECT annotation.
By specifying the batch size, you are telling Hibernate to retrieve the Cats in batches, saving on queries. If you retrieve 10 Persons, and the batch size is set to 100, you will only run 2 queries; 1 to get the Persons and 1 to get the Cats. If you retrieve 200 Persons, and the batch size is 100, you will run 3 queries; 1 to get the Persons and 2 to get the Cats collections. Its a win-win.