Hibernate – Difference between session’s get() and load() January 16th, 2007

Being an avid hibernate fan, I have always defended it in my organization when people throw undue criticism at it in order to protect themselves. In one such debate, a colleague pointed out a pattern in our code-base that introduced needless performance degradation, and condemned hibernate for it. I was glad he brought that up – for 2 reasons. First because, it sure was a problem and called for immediate attention. Second because, once again the problem was not with hibernate, but us. If you look closely at domain driven applications, you will notice that a few core objects are directly referenced by most other objects. Let me clarify what i mean with an example. In an auction application, for example, an Auction is held for an Item, a Bid is placed for an Item, a Buyer buys an Item. The common object referenced here is, well, an Item. This implies that whenever you create a new Auction or Bid you are constrained to supply a reference to Item. The most obvious way to achieve this is by getting a persistent instance of Item from the database using the session.get() method. This works, but it has its limitations.

Session session = << Get session from SessionFactory >>
Long itemId = << Get the item id from request >>

Item item = (Item) session.get(Item.class, itemId);

if(item != null) {
   Bid bid = new Bid();
   bid.setItem(item);
   session.saveOrUpdate(bid);
} else {
   // Handle the error condition appropriately
   log.error("Bid placed for an unavailable item");
}

Think about it… How many times will a bid be placed for an Item? Many… Every time a Bid is placed, is it wise to hit the database and retrieve the corresponding Item just to supply it as a reference? I guess not. That is where session.load() comes in. All the above scenarios remaining the same, if you just used session.load() instead of get(), hibernate will not hit the database. Instead it will return a proxy, or an actual instance if it was present in the current session, and that can be used to serve as a reference. What does this buy you? At least 2 advantages. First, you save a trip to the database. Second, the error handling code just got elegant. Take a look at the code snippet below. Here we don’t handle erroneous conditions using null checks. Instead we use exceptions, which sounds appropriate in this scenario. Don’t they?

Session session = << Get session from SessionFactory >>
Long itemId = << Get the item id from request >>

try{
   Item item = session.load(Item.class, itemId);
   Bid bid = new Bid();
   bid.setItem(item);
   session.saveOrUpdate(bid);
} catch(ObjectNotFoundException e) {
   // Handle the error condition appropriately
   log.error("Bid placed for an unavailable item");
}

From the above piece of code, it is obvious that, an ObjectNotFoundException may be thrown if the actual Item representing the given item id cannot be found. What i am not clear about – and neither is hibernate documentation – is which method is more likely to cause this exception and why? session.load() seems to have a possibility to throw this exception, and so does saveOrUpdate() for the same fact that item for the given id/proxy is not available. I would love to hear from people who have traveled this path and have an answer. Also, it would be wonderful, if you could point out other differences between session.get() and load() that i may have missed.

45 Responses to “Hibernate – Difference between session’s get() and load()”

  1. 1. Anonymous on January 16th, 2007 at 10:00 pm

    Right, this is the correct way to use load(). But note that in some cases the exception might not occur until transaction commit time. And in this case it might appear as a constraint violation, not an ONFE.

  2. 2. Anonymous on January 17th, 2007 at 4:31 am

    Being a beginner, it was really informative for me to learn the difference.

  3. 3. marcus on January 17th, 2007 at 7:44 am

    Great post. It’s those little things in rich tools like Hibernate that sharing of experiences like this is very helpful. Thanks!

  4. 4. Anonymous on January 17th, 2007 at 8:54 am

    Hibernate 3 API says:

    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.

    How this effects to your solution and what’s the reasoning behind that statement? Any ideas?

  5. 5. Anonymous on January 17th, 2007 at 3:10 pm

    Nice post – just so much to learn about Hibernate. Couldn’t you also use Hibernates 2nd level caching to help the performance and reduce trips to the database?

  6. 6. Anonymous on January 17th, 2007 at 3:11 pm

    Are there issues we should be worrying about when caching is enabled?

  7. 7. Anonymous on January 17th, 2007 at 3:53 pm

    As far as I know both calls will NOT cause a database hit if the object does exist in the session. And I think load will throw an ObjectNotFoundException if the object does not exist in the database. Thus it will cause a datbase hit if the object does NOT exist within the database session.

  8. 8. Anonymous on January 17th, 2007 at 4:00 pm

    If you are sure item is persisted in db then use load(), if you will check whether the item is persisted or not then use get(). if you will use load() then check whether the returned object is persisted then you may go wrong way. Because you load returns a proxy always, but get does not.

  9. 9. Simon Knott on January 17th, 2007 at 4:01 pm

    Am I missing something? In the latest API docs for the “get” methods in Hibernate 3.1/3.2 (which you link to), it quite clearly states:

    “If the instance, or a proxy for the instance, is already associated with the session, return that instance or proxy”

    This means that the only difference between the two methods is that the load method will throw an exception if the persistent entity does not exist in the database. The functionality you describe did exist in Hibernate 2, however.

  10. 10. Anonymous on January 17th, 2007 at 4:02 pm

    As far as I know if the object exist in the session both methods will not query the database but use the cached object. And as far as I understand load it has to query the database if the object does not exist within the session as it will throw an ObjectNotFoundException if the object does not exist. The javadoc isn’t quite clear there but if I remeber correctly that is the expected behaviour.

  11. 11. Anonymous on January 17th, 2007 at 4:04 pm

    As far as I know if the object exist in the session both methods will not query the database but use the cached object. And as far as I understand load it has to query the database if the object does not exist within the session as it will throw an ObjectNotFoundException if the object does not exist. The javadoc isn’t quite clear there but if I remeber correctly that is the expected behaviour.

  12. 12. Simon Knott on January 17th, 2007 at 4:04 pm

    Am I missing something? In the latest API docs for the “get” methods in Hibernate 3.1/3.2 (which you link to), it quite clearly states:

    “If the instance, or a proxy for the instance, is already associated with the session, return that instance or proxy”

    This means that the only difference between the two methods is that the load method will throw an exception if the persistent entity does not exist in the database. The functionality you describe did exist in Hibernate 2, however.

  13. 13. Paulo Pires on January 17th, 2007 at 4:41 pm

    I can see that this is your 2nd post but I hope that you’ll present “us” with many more as cool as this one :-)

    Any RSS feed?

    Cheers,
    PP

  14. 14. Anonymous on January 17th, 2007 at 5:19 pm

    This is a very good article and it triggered my curiosity. I have faced this issue few times. But not for performance issues. This is how I see it.
    The get method returns a persistent entity or null if the object does not exist. If the object is already in the session, return that instance or proxy.
    The load method:
    – load (Class, Serializable), you should use find to check the existance of the entity. Don’t assume that the object exists. This method retrieves that persistent object. If the object is already in the session, return the instance or the proxy.
    – load(Object, Seriablizable), gets the persistent state for gievn Id into transient object (Object not associated with session).
    As far as the performance, I benchmarked both and I have not seen any difference.

  15. 15. Ganeshji Marwaha on January 17th, 2007 at 8:03 pm

    Honestly, i didn’t anticipate this many responses. In fact, i would be understating, when i say “you made my day”. As i have assured in my first post, my intent is to share and learn at the same time. I will cast my best efforts in the upcoming entries to live up to it. Thanks to all my new friends, who took the patience to listen to me.

    After studying the adept responses above, i was able to do a more informed research on the topic. Here, assuming we use the load() method, lets pinpoint when a proxy will be returned, and when an ObjectNotFoundException will be thrown.

    Scenario #1: Item entity is configured such that hibernate is allowed to proxy it.

    In this case, if the Item instance exists in the session cache, it will be returned, otherwise a proxy will be returned. If an actual instance was returned in the first place, we will be fine when we access Item’s properties. If a proxy was returned to begin with, then an ObjectNotFoundException will be thrown if we access the properties of the Item proxy, and the actual Item doesn’t exist in the database.

    Note: You may access the identifier property without raising the exception.

    Scenario #2: Item entity is configured such that hibernate is not allowed to proxy it.

    In this case, hibernate will try to return the actual instance always. So, if an instance exists in the session cache, it will be returned. If not, since hibernate is not allowed to proxy it, it will make a trip to the database to find the instance. If present, the instance will be added to the session cache and returned. Otherwise, an ObjectNotFoundException will be thrown.

    Hope this clarifies.

  16. 16. Ganeshji Marwaha on January 17th, 2007 at 8:07 pm

    I can see that this is your 2nd post but I hope that you’ll present “us” with many more as cool as this one :-)

    Any RSS feed?

    Cheers,
    PP

    Here you go. http://gmarwaha.blogspot.com/atom.xml

    The right nav-bar in the main page has a link to this feed, but i guess, i didn’t add it to the individual post entries when i was updating my blogger template.

  17. 17. Anonymous on January 17th, 2007 at 10:51 pm

    Nice post. Encourages me to learn more about Hibernate

  18. 18. Anonymous on January 19th, 2007 at 11:15 pm

    how about the penalty you take for switching from a simple if/else check, to a try/catch which is a more expensive operation

  19. 19. Ganeshji Marwaha on January 20th, 2007 at 1:28 am

    I agree that try-catch has a slight penalty compared to a null-check. Still there are 3 other reasons why you will want to use try-catch in this scenario.

    1. In most cases, get() will return an object (primary reason for using load() here), which constrains us to hit the database twice – once for get() and again for saveOrUpdate(). This is far more expensive than using load() with try-catch.

    2. Shouldn’t we prefer an elegant approach compared to a minor increase in performance.

    3. The exception is caught and handled early, which more than halves the penalty introduced.

    Either ways, i appreciate the different perspective you brought.

  20. 20. Anonymous on January 24th, 2007 at 8:40 am

    Have you tried to use load() twice in one session for a given ID? Then you’ll see why this is not such a good idea, as you’ll get an exception stating that the object with the given identifier cannot be loaded as it is already associated with the current session.

    You can either evict it from the session before, or use get (which has my preference). I would also use either lazy loading or caching for this performance optimization, and certainly not load().

  21. 21. Anonymous on January 24th, 2007 at 8:53 am

    I don’t think using load() is a good idea for this performance optimization. Have you ever tried to use load() twice in the same session for a given ID? Then you’ll get an exception stating that the object with the given ID has already been associated with the session and can thus not be loaded anymore.

    I would use caching or lazy loading for this performance optimization, and certainly would not use load().

    Please note that get() will only hit the DB if:
    - the object is not associated with the session
    - is not present in the 2nd level cache

  22. 22. Ganeshji Marwaha on January 24th, 2007 at 9:23 am

    I am in accord with some of your opinions but beg to differ on the rest.

    Second level cache is undeniably an option, but if i were you, i would consider it as the last resort. I completely agree that get() will hit the DB only when the instance is not in session cache. I thought i mentioned it in my post, but i realized that i haven’t after i read your comment. Good catch, thanks. But to be honest, this optimization technique is for when it is not.

    Calling load() twice within a session (for the same id) does not throw any exceptions. You might want to double check and we can talk about this later if you prefer.

    How exactly can we use lazy loading to achieve performance optimization in this scenario? Assuming the instance is not in session, a call to get() will result in a DB trip regardless of whether you have configured it to be lazily loaded or not. So, i wouldn’t bet on this. Again, feel free to correct me if i am wrong.

  23. 23. Anonymous on January 25th, 2007 at 2:09 pm

    It´s very simple:

    use session.load when you are sure that the object exists in your application. session.load always returns a proxy

    use session.get when the object could not exists. if the object didn´t exists return null

  24. 24. Anonymous on January 25th, 2007 at 4:23 pm

    On your comment..
    “Second because, once again the problem was not with hibernate, but us.”

    One thing you should realize is that with hibernate the problem will always be with us. That’s because it is pretty complicated to use. It may be rich in functionality but it is overly complex. A good tool/library should always have a very fast/easy learning curve. What is the point of good library if only very few people can use it right? Is it the fault of the people using it or the library? Something to ponder over…
    cheers

  25. 25. Anonymous on February 1st, 2007 at 10:15 am

    Please note the difference between ‘void load(..)’ and ‘Object load(..)’. I checked the Hibernate sources, and for the ‘Object load(..)’ I found the following (confirming my statement about loading an Object with the same ID twice in a session) in org.hibernate.event.def.DefaultLoadEventListener:

    /**
    * Perfoms the load of an entity.
    *
    * @return The loaded entity.
    * @throws HibernateException
    */
    protected Object load(
    final LoadEvent event,
    final EntityPersister persister,
    final EntityKey keyToLoad,
    final LoadEventListener.LoadType options)
    throws HibernateException {

    if ( event.getInstanceToLoad() != null ) {
    if ( event.getSession().getPersistenceContext().getEntry( event.getInstanceToLoad() ) != null ) {
    throw new PersistentObjectException(
    “attempted to load into an instance that was already associated with the session: ” +
    MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
    );
    }
    persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), event.getSession().getEntityMode() );
    }

    Sorry for the formatting, but I’m not allowed to use the appropriate HTML-tags…
    You’re right that ‘void load(..)’ does not throw such an exception, when the instance is already associated with the session.

  26. 26. Anonymous on March 5th, 2007 at 10:39 am

    Real good discussion. Nice stuff Ganesh.

  27. 27. James on March 24th, 2007 at 7:38 pm

    The fact that calling Object load() twice in a single session throws an Exception (NonUniqueObjectException) is not a failing of Hibernate at all – in fact, it’s unavoidable.

    When Hibernate loads an Object with load() (or with get() for that matter), the Object is always persistent – i.e., associated with the session. (Contrast this with merge(), where the object passed in remains transient or detached.) Therefore, the Object you pass in to load needs to return as a persistent Object. Those are the semantics of the method. Hibernate obviously can’t have two separate persistent Java objects for one database record – if it did, how would it know which one’s state to save?

    If there were a get() method to load state into an existing Object, it would do precisely the same thing, but having such a method wouldn’t be logical – since get() can’t load null state into the existing Object, and returning null is pretty much get()’s only purpose.

    The difference with the Object-returning method is that, if there is an existing persistent Object already associated with the session, it just returns that Object – and therefore doesn’t have the duplicate reference problem. (Hibernate refers to these internally as reload and load events respectively.)

    It was mentioned above that Hibernate is too complicated. Perhaps the real problem is that it looks so much easier than it is. A lot of people get confused about things like the one I just mentioned because they think of Hibernate as a simple wrapper around a database, whereas it’s actually a fundamental shift in thinking about persistence. Anyway, good article – if only for the discussion it provoked.

  28. 28. Chet on October 22nd, 2007 at 11:03 am

    Hi Ganesh,

    Good post, though I seem to be reading it pretty late :) .

    I have a somewhat similar problem and thought you might interested in giving some input. Though Hibernate is not new to me, but the current project that I am handling is about 6 months old. And now we have the requirement of splitting the application into 2 (or more) parts. Since that was not an original requirement, the simple design of this application did not take into account this possibility.

    The scenario is simple enough, with Hibernate configuration files and POJO files forming a layer between the service layer and the MySQL database. In the front end we have Struts based action classes. The service layer, creates a Hibernate session and uses it for the purpose and discards it on use. Now if we split the application, into 2 parts, there is bound to be sync problem between the 2 hibernate sessions each part creates.

    So my problem is “how do we maintain the two hibernate sessions in sync”? Any alternate solution to this existing system can also be applied.

    Thanks for you patience !!
    Chet

  29. 29. Berdam on April 8th, 2008 at 12:40 am

    The time for insert, used load is lower of the used get?????

  30. 30. Oyun on September 11th, 2008 at 10:09 pm

    very thanks for you!! OyunX

  31. 31. Victor Hernandez on November 17th, 2008 at 7:44 pm

    HI, I WANT TO KNOW IF IS POSSIBLE TO ADD A PAUSE BUTTON TO THE CARROUSEL WHEN AUTOSCROLL IS ENABLED.

    THANKS AND… GREAT WORK!!

  32. 32. darsane on June 16th, 2009 at 4:53 pm

    Thank you for information.

  33. 33. okey oyna on October 27th, 2009 at 11:13 am

    The time for insert, used load is lower of the used get?????

  34. 34. okey oyna on October 27th, 2009 at 11:16 am

    Large organisations – both public and private – can be well known for being inflexible. But for initiatives like this (and those in the future) to have a better chance of succeeding we need to look at how we can bring down the barriers to change. This is too big an issue to get in to here it and the reasons are both big and many, from too many stakeholders requiring approval to a ‘wait until the summer vacation’ philosophy, from long term budget planning to knock-on affects across the organisation (change in department A means training/documentation/website of Department B needs to be changed first). Hmmmm, seemed to have moved away from TILE and on to a general rant offending the entire UK HE sector!

  35. 35. okey oyna on February 20th, 2010 at 10:14 pm

    HI, I WANT TO KNOW IF IS POSSIBLE TO ADD A PAUSE BUTTON TO THE CARROUSEL WHEN AUTOSCROLL IS ENABLED.

    THANKS AND… GREAT WORK!!

  36. 36. paul on November 15th, 2010 at 2:10 am

    Hi,

    great post. very informative. i also came to this site telling difference between the get() and load() methods of Hibernate?

    http://www.adobocode.com/spring/hibernate-difference-between-load-and-get-methods

    which one is best for a certain scenario? can you give a sample on when to use load() and when to use get() ?

    Thanks.

  37. 37. abercrombie uk on January 14th, 2011 at 8:04 am

    Get is when you get when you call to operate database
    Load is different
    When using the load method inquires session in the database records, we return to a proxy objects, not really need that object

  38. 38. epoksi on March 22nd, 2011 at 12:53 am

    HI, I WANT TO KNOW IF IS POSSIBLE TO ADD A PAUSE BUTTON TO THE CARROUSEL WHEN AUTOSCROLL IS ENABLED.

  39. 39. cam balkon on March 22nd, 2011 at 12:54 am

    When using the load method inquires session in the database records, we return to a proxy objects, not really need that object

  40. 40. cam balkon on March 22nd, 2011 at 12:54 am

    Get is when you get when you call to operate database
    Load is different.

  41. 41. cam balkon on March 22nd, 2011 at 12:56 am

    If there were a get() method to load state into an existing Object, it would do precisely the same thing, but having such a method wouldn’t be logical – since get() can’t load null state into the existing Object, and returning null is pretty much get()’s only purpose.

  42. 42. tadilat on March 22nd, 2011 at 12:57 am

    which one is best for a certain scenario? can you give a sample on when to use load() and when to use get.

  43. 43. Link Building Services on January 8th, 2012 at 4:05 pm

    HI, I WANT TO KNOW IF IS POSSIBLE TO ADD A PAUSE BUTTON TO THE CARROUSEL WHEN AUTOSCROLL IS ENABLED.

  44. 44. online contest on February 28th, 2012 at 1:46 pm

    As a hibernate fan I honestly aggressive to know about the difference between session’s get() and load(). I guess this info would be helpful for me. Thanks!

  45. 45. PTO pellet mill on March 2nd, 2012 at 6:35 am

    You will use less energy overall even when you warm up your house from a cooler temperature.