Hibernate – Difference between session’s get() and load()

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.

Ganeshji Marwaha

I spend my days as the Director of Technology for Mobility practice and help my clients design enterprise and consumer mobile strategies. Mobile Payments, Digital Wallet and Tokenization technologies are my areas of specialization

  • Anonymous

    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.

  • Anonymous

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

  • marcus

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

  • Anonymous

    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?

  • Anonymous

    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?

  • Anonymous

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

  • Anonymous

    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.

  • Anonymous

    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.

  • Simon Knott

    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.

  • Anonymous

    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.

  • Anonymous

    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.

  • Simon Knott

    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.

  • Paulo Pires

    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

  • Anonymous

    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.

  • Ganeshji Marwaha

    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.

  • Ganeshji Marwaha

    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.

  • Anonymous

    Nice post. Encourages me to learn more about Hibernate

  • Anonymous

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

  • Ganeshji Marwaha

    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.

  • Anonymous

    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().

  • Anonymous

    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

  • Ganeshji Marwaha

    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.

  • Anonymous

    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

  • Anonymous

    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

  • Anonymous

    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.

  • Anonymous

    Real good discussion. Nice stuff Ganesh.

  • James

    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.

  • Chet

    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

  • Berdam

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

  • very thanks for you!! OyunX

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

    THANKS AND… GREAT WORK!!

  • Thank you for information.

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

  • 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!

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

    THANKS AND… GREAT WORK!!

  • 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.

  • 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

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

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

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

  • 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.

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

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

  • 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!

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