1. Introduction

In Hibernate, load() and get() are two methods used to retrieve data from the database. In this tutorial, we’ll explore the differences between these methods.

2. Loading Strategy

The load() method in Hibernate employs a lazy loading strategy. When invoked, it returns a proxy object of the entity, delaying the database query until a property or method of the object is accessed. Here’s how it works:

Person person = new Person("John Doe", 30);

Session session = sessionFactory.getCurrentSession();
session.saveOrUpdate(person);

Person entity = session.load(Person.class, person.getId());

assertNotNull(entity);
assertEquals(person.getName(), entity.getName());
assertEquals(person.getAge(), entity.getAge());

First, we create a new Person object and save it to the database. Then, we use load() to retrieve the Person entity with the saved Person‘s id. Although the entity appears to be a Person object, it’s a proxy object provided by Hibernate.

When we access the properties of the proxy object, such as name and age, Hibernate intercepts the calls and dynamically loads the actual data from the database if necessary. Conversely, the get() method employs an eager loading strategy, which immediately queries the database and returns the actual entity object:

Person entity = session.get(Person.class, person.getId());

assertNotNull(entity);
assertEquals(person.getName(), entity.getName());
assertEquals(person.getAge(), entity.getAge());

3. Return Value When Data Exists

When we invoke the load() method, Hibernate creates a proxy object of the entity with the provided primary key id. This proxy object serves as a placeholder for the entity data, with only the id populated. The remaining properties of the entity are uninitialized and will be loaded from the database when accessed for the first time. If we try to access any property of the proxy object without initializing it, we’ll get a LazyInitializationException:

Session session = sessionFactory.openSession();
session = sessionFactory.openSession();
Person entity = session.load(Person.class, person.getId());

// Close the session
session.close();

assertThrows(LazyInitializationException.class, () -> {
    entity.getName();
});

On the other hand, the get() method directly retrieves the actual entity data from the database. This means that the entity object returned by get() contains all the initialized properties with their actual values fetched from the database. Therefore, even after the Hibernate session is closed, we are still able to access the properties of the entity without any exception:

Session session = sessionFactory.openSession();
session = sessionFactory.openSession();
Person entity = session.get(Person.class, person.getId());

// Close the session
session.close();

// Access entity properties even after session closure
assertEquals(person.getName(), entity.getName());
assertEquals(person.getAge(), entity.getAge());

4. Behavior When Data Doesn’t Exist

When using load(), it initially returns a proxy object. The actual database query is deferred until we access a property of the object. If the entity doesn’t exist, attempting to access the object’s properties will result in an ObjectNotFoundException. Therefore, we need to handle this situation explicitly:

Session session = sessionFactory.getCurrentSession();
Person entity = session.load(Person.class, 100L);

 // Access properties of the entity, triggering the database query
assertThrows(ObjectNotFoundException.class, () -> {
    entity.getName();
});

In contrast, when using the get() method, if the entity is present in the database or cache, it retrieves and returns the actual entity object immediately. However, if the entity doesn’t exist, get() gracefully returns null:

Session session = sessionFactory.getCurrentSession();
Person entity = session.get(Person.class, 100L);
assertNull(entity);

5. Caching

Both load() and get() methods utilize the first-level cache to cache retrieved entities within the current session. It stores the entities that have been recently accessed or manipulated within the current session. If the object already exists in the cache, get() will return the cached object immediately. However, load() will still return a proxy object even though the data might be cached.  Here’s an example to illustrate this behavior:

Person person = new Person("John Doe", 30);

Session session = sessionFactory.openSession();
session.saveOrUpdate(person);
Person entity = session.get(Person.class, person.getId());

// Evict the entity from the session cache to simulate a new session
session.evict(entity);

Person cacheEntity = session.get(Person.class, person.getId());

When we create a Person entity to the session, Hibernate caches the entity. Subsequently, we invoke the first get() method. Since the entity is in the cache, Hibernate will not hit the database. Then, we evict the entity from the session cache to simulate starting a new session.

We then use the get() method to retrieve the entity again. This time, since the entity is not in the cache, Hibernate will hit the database. From the output console, we can see that only one SQL select statement was printed by Hibernate:

Hibernate: select p1_0.id,p1_0.age,p1_0.name from Person p1_0 where p1_0.id=?

6. Summary

Let’s summarize the key differences between the get() and load() methods in Hibernate:

Feature

get()

load()

Loading Strategy

Eager loading (immediate database query)

Lazy loading (proxy object, data fetched on access)

Return Value (if exists)

Actual object

Proxy object

Database Query

Executes immediately

Executes when a property is accessed

Return Value (if not exists)

null

Results in an ObjectNotFoundException when accessing properties

Hibernate Cache

Retrieves from the cache if present

Still returns proxy even if cached

7. Conclusion

In this article, we’ve explored the fundamental differences between the get() and load() methods in Hibernate. The get() method is useful when we need to access the object immediately and ensure that it is up-to-date. On the other hand, the load() method is useful when we only need to reference the object and optimize database calls.

As always, the source code for the examples is available over on GitHub.