Hibernate Gotchas and Growing Pains

This blog entry is a TODO, but I wanted to have a place to jot down a few pains with Hibernate and how to remedy them.

1. @ManyToOne id references result in a query by default.

Eg:

class Dog {
protected @ManyToOne owner;
}

Dog dog = entityManager().find(Dog.class, 1);
System.out.println(dog.owner.id); // This results in the Owner class being queried which is not necessary.

The basic solution which I will detail out later is to set property access on the id attribute of Owner, while leaving everything else the default (field).

2. The nasty query cache.

Using the example above and querying the dog class as follows:
Query query = entityManager().createQuery("select o from Dog o");
query.setHint("org.hibernate.cacheable", true);
return query.getResultList();

Results in the query being cached. This is nice in cases where you have an expensive query and since all that is cached is a list of ids, it seems pretty harmless.

One problem here: Overlapping queries. If the underlying 2nd cache becomes invalid before the query cache, instead of re-executing the query, you get N selects for each id that has been cached and invalidated.

Example: Let's say you have your Dog class cache and your query cache TimeToLive set to 10 minutes.
Now you execute a query "select o from Dog o where o.id > 1" which you have cacheable true as well. Then 9 minutes later you execute the above code. After waiting 1 minute, all the objects from the first query have become invalid. So if you hit the above code again, instead of the query being executed, hibernate will try and fetch every object that has been invalidated from the first query.

3. Understanding @Version

Here I want to outline how @Version works and problems with it:

Updates on Version when any part of the object graph has been modified.
Null versions
Cache Problems, Partial Updates (due to programmer error)