SQL Zone is brought to you in partnership with:

Nicolas Frankel is an IT consultant with 10 years experience in Java / JEE environments. He likes his job so much he writes technical articles on his blog and reviews technical books in his spare time. He also tries to find other geeks like him in universities, as a part-time lecturer. Nicolas is a DZone MVB and is not an employee of DZone and has posted 231 posts at DZone. You can read more from them at their website. View Full User Profile

Hibernate Hard Facts – Part 4

02.18.2010
| 8772 views |
  • submit to reddit
In the fourth article of this series, I will show the subtle differences between get() and load() methods.

Hibernate, like life, can be full of suprises. Today, I will share one with you: have you ever noticed that Hibernate provides you with 2 methods to load a persistent entity from the database tier? These two methods are get(Class, Serializable) and load(Class, Serializable) of the Session class and their respective variations.

Strangely enough, they both have the same signature. Strangely enough, both of their API description starts the same:

Return the persistent instance of the given entity class with the given identifier.

Most developers use them indifferently. It is a mistake since, if the entity is not found, get() will return null when load() will throw an Hibernate exception. This is well described in the API:

Return the persistent instance of the given entity class with the given identifier, assuming that the instance exists. You should not use this method to determine if an instance exists (use get() instead). Use this only to retrieve an instance that you assume exists, where non-existence would be an actual error.

Truth be told, the real difference lies elsewhere: the get() method returns an instance, whereas the load() method returns a proxy. Not convinced? Try the following code snippet:

Session session = factory.getCurrentSession();

Owner owner = (Owner) session.get(Owner.class, 1);

// Test the class of the object
assertSame(owner.getClass(), Owner.class);  

The test pass, asserting that the owner’s class is in fact Owner. Now, in another session, try the following:

Session session = factory.getCurrentSession();

Owner owner = (Owner) session.load(Owner.class, 1);

// Test the class of the object
assertNotSame(owner.getClass(), Owner.class);

The test will pass too, asserting that the owner’s class is not Owner. If you spy the object in the debugger, you’ll see a Javassist proxyed instance and that fields are not initialized! Notice that in both cases, you are able to safely cast the instance to Owner. Calling getters will also return expected results.

Why call the load() method then? Because since it is a proxy, it won’t hit the DB until a getter method is called.

Moreover, these features are also available in JPA from the EntityManager, respectively with the find() and getReference() methods.

Yet, both behaviours are modified by Hibernate’s caching mechanism. Try the following code snippet:

// Loads the reference
session.load(Owner.class, 1);

Owner owner = (Owner) session.get(Owner.class, 1);

According to what was said before, owner’s real class should be the real McCoy. Dead wrong! Since Hibernate previously called load(), the get() looks in the Session cache (the 1st level one) and returns a proxy!

The behaviour is symmetrical with the following test, which will pass although it’s counter-intuitive:

// Gets the object
session.get(Owner.class, 1);

// Loads the reference, but looks for it in the cache and loads
// the real entity instead
Owner owner = (Owner) session.load(Owner.class, 1);

// Test the class of the object
assertSame(owner.getClass(), Owner.class);

Conclusion: Hibernate does a wonderful job at making ORM easier. Yet, it’s not an easy framework: be very wary for subtle behaviour differences.

The sources for the entire hard facts serie is available here in Eclipse/Maven format.

From http://blog.frankel.ch/

Published at DZone with permission of Nicolas Frankel, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Michael Parmeley replied on Thu, 2010/02/18 - 4:32pm

I constantly see articles about getting around Hibernate surprises and gotchas and then the same articles always says Hibernate makes ORM easier. Suprises/gotchas seem to be mutually exclusive to making something easier.

 I have always thought and nothing has yet changed my mind (even after using Hibernate) that Hibernate is a solution looking for a problem. It may eliminate JDBC boiler-plate but it replaces it with its own boiler-plate and is far more complex thatn JDBC.

Nicolas Frankel replied on Fri, 2010/02/19 - 2:34am

It is only the 80/20 rule that you can apply to all frameworks... In this case, Hibernate makes it easier in 80% of the cases. It's the remaining 20% you have to look for.

Roy Grini replied on Fri, 2010/02/19 - 2:36am in response to: Michael Parmeley

It is definately not a solution looking for a problem. It is a very good abstraction of a complicated issue. But as with anything abstracting something else also Hibernate will suffer by the 'Law of leaky abstractions'.

 

Roy

Dimitris Menounos replied on Fri, 2010/02/19 - 3:55am

I like hibernate, however strive to use the less of its magic I can. Among other things, I don't use session.load() / entityManager.getReference() and always work with detached objects.

Ganeshji Marwaha replied on Sun, 2010/02/21 - 4:30am

You can find a similar explanation for the same here. http://www.gmarwaha.com/blog/2007/01/16/hibernate-difference-between-sessions-get-and-load/

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.