by Jim White (Instructor and Director of Training)
Last week, I had a group of experienced Java developers attend my Complete Hibernate class. They had several great questions, some of which I plan to highlight with a few blog posts over the next week or so. In today's post, I would like to address how the overloaded load( ) methods work in Hibernate (this question was posed by Chris - thanks for the great questions Chris).
Retrieving A Persistent Instance in Hibernate
First off, a bit of background. There are two methods that can be used on a Hibernate session (org.hibernate.Session) to retrieve a single instance of persistent object: get( ) and load( ). In fact, both methods are heavily overloaded, meaning there are several methods with the same name but that take different parameters. So in fact there are far more than two methods. While both get( ) and load( ) methods retrieve a persistent object by its identifier, these two types of methods operate a little differently.
Difference Between get( ) and load( )
The get( ) methods always hit the database. Meaning, as soon as the call to get( ) occurs, Hibernate issues an SQL statement to the database in an attempt to fetch the associated data (usually a row in the database) to rebuild the requested persistent object. A call to load( ), on the other hand, does not immediately incur a call to the database. The load( ) method causes a proxy object to be constructed as a stand-in for the persistent object. It is only after some state is requested from the proxy that Hibernate issues the appropriate SQL to the database and builds the real persistent object. When using get( ), the method will return null if no data exists for the requested identifier. Since the load( ) method does not immediately retrieve the object, if no data exists for the identifier used to retrieve the object, an ObjectNotFoundException is thrown once data is requested of the proxy.
Overloaded get( ) and load( ) Methods
As I mentioned, both the get( ) and load( ) methods are heavily overloaded. There are four of each methods that take the same parameters: the class (either a Class object or String name), persistent object identifier, and optionally a lock mode (for pessimistic locking). The four methods of each are outlined in the table below.
| get(Class clazz, Serializable id) |
| load(Class clazz, Serializable id) |
| get(Class clazz, Serializable id, LockMode lockMode) |
| load(Class clazz, Serializable id, LockMode lockMode) |
| get(String className, Serializable id) |
| load(String className, Serializable id) |
| get(String className, Serializable id, LockMode lockMode) |
| load(String className, Serializable id, LockMode lockMode) |
An Extra load( ) Method
There is an additional load( ) method that was at the heart of Chris's question. The last of the overloaded load( ) methods takes an existing instance of the persistent class and the identifier of the persistent instance to be retrieved.
load(Object object, Serializable id)
This load( ) method will read the persistent state of the requested object directly into the existing instance provided. In fact, since you pass in the instance whose properties are to be set with state, the method returns void. What's more, like the get( ) method, it will cause Hibernate to issue an SQL request immediately to the database. Care must be taken with this method in that any state that exists in the object passed to the method will be replaced by data found in the database - even the id will be replaced by the id of the persistent object retrieved!
To see how load(Class clazz, Serializable id) differs from load(Object object, Serializable id), take a look at the two sections of code below, each followed by the output issued from the code when executed.
Example of using load(Class clazz, Serializable id)
public static void main(String[] args) {
SessionFactory sf = new Configuration().configure()
.buildSessionFactory();
Session session = sf.openSession();
Contact c = (Contact)session.load(Contact.class, 1L);
System.out.println("Before any request of the proxy or persistent object -------.");
System.out.println("Contact retrieved ---- >" + c);
System.out.println("After a request of the proxy or persistent object -------.");
session.close();
}
Output from example above
Before any request of the proxy or persistent object -------.
Hibernate:
select
contact0_.id as id0_0_,
contact0_.first_name as first2_0_0_,
contact0_.last_name as last3_0_0_,
contact0_.date_of_birth as date4_0_0_,
contact0_.married as married0_0_,
contact0_.children as children0_0_,
contact0_.org_id as org7_0_0_,
contact0_.spouse_name as spouse8_0_0_,
contact0_.spouse_date_of_birth as spouse9_0_0_,
datediff('yy',
contact0_.date_of_birth,
curdate()) as formula0_0_
from
Contact contact0_
where
contact0_.id=?
Contact retrieved ---- >Jim White(1)
After a request of the proxy or persistent object -------.
Notice how, in this example, SQL is not issued until data from the Contact object is used (as part of the toString in the println request).
Example of using load(Object object, Serializable id)
public static void main(String[] args) {
Contact c = new Contact();
c.setId(1234L);
c.setFirstName("John");
c.setLastName("Doe");
SessionFactory sf = new Configuration().configure()
.buildSessionFactory();
Session session = sf.openSession();
session.load(c, 1L);
System.out.println("Before any request of the proxy or persistent object -------.");
System.out.println("Contact retrieved ---- >" + c);
System.out.println("After a request of the proxy or persistent object -------.");
session.close();
}
Output from example above
Hibernate:
select
contact0_.id as id0_0_,
contact0_.first_name as first2_0_0_,
contact0_.last_name as last3_0_0_,
contact0_.date_of_birth as date4_0_0_,
contact0_.married as married0_0_,
contact0_.children as children0_0_,
contact0_.org_id as org7_0_0_,
contact0_.spouse_name as spouse8_0_0_,
contact0_.spouse_date_of_birth as spouse9_0_0_,
datediff('yy',
contact0_.date_of_birth,
curdate()) as formula0_0_
from
Contact contact0_
where
contact0_.id=?
Before any request of the proxy or persistent object -------.
Contact retrieved ---- >Jim White(1)
After a request of the proxy or persistent object -------.
Using load with an existing object, you see that SQL is issued immediately (even before a request of the object is made). The data retrieved replaces all the existing data in the Contact object (referenced here as 'c') during the load operation.
As with other forms of the load( ) method, an ObjectNotFoundException is the result when you try to retrieve an object with an identifier that does not exist. However, because SQL is immediately issued to populated the existing object, the exception is thrown on the call to load( ). In contrast, the ObjectNotFoundException will be thrown when accessing the proxy produced by other forms of the load( ) method.
Wrap Up
So while get( ) and load( ) methods on Hibernate's session object each have the same ultimate purpose (to retrieve a persistent instance) both behave a bit differently. And, in fact, as you've seen there are also some differences in the behavior of various forms of the overloaded load( ) method. If you would like to learn more about Hibernate, I encourage you to take Intertech's Complete Hibernate course. We'd love to have you in our classroom, but you can also take the class virtually.
ceb66650-5bd5-427d-b37a-4cedab10590e|3|2.3