Search This Blog

Friday, 23 March 2012

get() versus load()

This has to be one of the most popular questions asked in hibernate interviews:
What is the difference between get() and load() method ?
Hibernate provides us with the two methods to load a persistent entity from the database. These signatures are session.get(Class, Serializable) and session.load(Class, Serializable). Both methods take a class variable and an identifier object and return an instance of the Entity class.
The most common answer that people (including me before I learned this) give is :
If the entity is not found in the database, get() will return null while load() will throw an Hibernate exception.
But why ? Hibernate wouldn't provide two methods that did the same action but would be distinguished by their handling of missing rows ? Or is that the case ?
The real difference is that the get() method actually loads and returns the record from the database whereas the  load() method only returns a proxy.
static void checkDifference() {
    Session session = sessionFactory.openSession();
    Entity entity1 = (Entity) session.load(Entity.class, 1);
    System.out.println("Entity 1: " + entity1.getClass());
    Entity entity2 = (Entity) session.get(Entity.class, 2);
    System.out.println("Entity 2: " + entity2.getClass());
}
The console displays the class types:
Entity 1: class com.model.Entity$$EnhancerByCGLIB$$b82499d4
Entity 2: class com.model.Entity
The logs indicate that for the get call:
  1. Hibernate fired a select query and fetched the record from the database.
  2. It then added the object to the persistence cache.
For the load call:
  1. Hibernate creates a proxy object and no select query is fired.
  2. As no data was fetched no insertions are performed in the persistence cache.
In fact if the above code is executed with an id 999 (record does not exist), the code will still work fine.Hibernate does not throw any exception.As there has been no database hit, Hibernate very happily creates a proxy with the id 999.
However if we try to access one of the fields using a getter call then:
static void checkDifference() {
    Session session = sessionFactory.openSession();
    Entity entity1 = (Entity) session.load(Entity.class, 999);
    System.out.println("hashcode is " + entity1.hashCode());
    System.out.println("equals is " + entity1.equals(new Entity()));
    System.out.println("The data is " + entity1);
}
Even a simple toString call results in the below error.
hashcode is 4815156
equals is false
Exception in thread "main" org.hibernate.ObjectNotFoundException: No row with th
e given identifier exists: [com.model.Entity#999]
    at org.hibernate.impl.SessionFactoryImpl$1.handleEntityNotFound(SessionFactoryI
mpl.java:377)
    at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyIni
tializer.java:79)
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializ
er.java:68)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyIn
itializer.java:111)
    at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitiali
zer.java:150)
    at com.model.Entity$$EnhancerByCGLIB$$b82499d4.toString(<generated>)
The call to toString() or any of the getters() results in Hibernate attempting to fetch the record from database. And I haven't  overloaded any methods. All calls for toString(),hashCode() and equals() went to the Object class.
As no record with id 999 exists the exception is thrown.
If load() does not result any data fetch then why use it ??
Consider the creation of an entity which also involves an association.
Session session = sessionFactory.openSession();
Entity entity1 = new Entity();
Parent parent = (Parent) session.load(Parent.class, 9);
entity1.setParent(parent);
Here we are trying to create a new instance of entity. We need to create the association between entity and the parent. It is only the identifier of parent that is necessary for this operation. As no parent data is necessary for this, Hibernate is saved the firing of the select query. The proxy contains the minimum information necessary - the identifier - this is all that is needed to create the above association.
In the next post we shall see what happens  if we get and load the same object in one session ? Also how do associations behave when we get or load objects?

No comments:

Post a Comment