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.

Hibernate and HSQLDB

Monday, May 5. 2008

Here is an example of how to pass properties to HSQLDB without having an explicit properties file. These properties tell HSQLDB to shutdown after the last connection is closed, to only store records being accessed in memory (store the rest on disk), and to store no more than 12Mb worth of records in memory.

<!-- JDBC connection properties -->
<property name="hibernate.connection.driver_class">
    org.hsqldb.jdbcDriver
</property>
<property name="hibernate.connection.url">
    jdbc:hsqldb:file:hsqldb;
    shutdown=true;
    hsqldb.default_table_type=cached;
    hsqldb.cache_scale=12;
    hsqldb.cache_size_scale=10
</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.hbm2ddl.auto">create-drop</property>
<property name="hibernate.show_sql">false</property>


No other startup or shutdown configuration is necessary.