I consider Hibernate a great and useful tool. But it has some mean Exceptions lurking in the darker corners. Today I'd like to explore the ones from the title in a little more detail, including different approaches on how to avoid them.

Let's start with the well known LazyInitializationException. When you search for this one in the Internet you end up with scenarios like this one:

You load A, close the session you  used and try to access a property of A which gets loaded lazily resulting in a LazyInitializationException. That one is well described, including strategies to avoid it, which basically consist of not closing the session to early.

But there are more hideous scenarios. Assume the classes Mom, Dad and Kid are mapped as one would expect, with references from Mom and Dad to Kid. Now consider the following piece of code:

Session session = openSession();
session.beginTransaction();

Mom mom = (Mom) session.load(Mom.class, momId);
Kid momsKid = mom.getKid();

// dad comes by
Dad dad = (Dad) session.load(Dad.class, dadId);
Kid dadsKid = dad.getKid();

// and leaves
session.evict(dad);

// alas he has taken kido with him
momsKid.getName();


Depending on your exact Mapping you might get a LazyInitializationException in the last line, although the session is still open. The problem here is that when dad got evicted the kid got evicted as well. And since Mom has a reference to the exact same object, that object isn't attached to any session anymore. In order to see this effect you'll have to use mappings like this:

    @ManyToOne(fetch = LAZY, cascade = CascadeType.ALL)
@Cascade(org.hibernate.annotations.CascadeType.ALL)
private Kid kid;

The NonUniqueObjectException gets caused by what could be considered the reverse process. Examine the following piece of code:

        // Dad left for another woman, I mean Session
Dad dad = loadDad();

Session session = openSession();
session.beginTransaction();

Mom mom = (Mom) session.load(Mom.class, momId);
System.out.println(mom.getKid().getName());

// Now dad wants to move back in
session.saveOrUpdate(dad);


The first method call loads a Dad object including Kid from a different session. Then from the 'main' session Mom gets loaded including kid. When we attach the Dad object to the session it tries to attach its version of the Kid as well, which collides with the Kid already present in the session.

So how can we avoid these kind of problem? I see several options:


If you want the complete source code for the example, you can download this source.zip file.