In an application, Hibernate fetches data from the database either in eager or lazy mode. Lazy loading refers to a strategy where data is loaded lazily on-demand when the application needs to access it.
1. Need for Lazy Loading
Consider one of the common Internet web applications: the online store. The store maintains a catalog of products (call it a Category). At the crudest level, this can be modeled as a Category entity managing a series of Product entities. In a large store, there maybe tens of thousands of products grouped into various overlapping categories.
When a customer visits the store, the categories must be loaded from the database. We probably don’t want the application to load every single one of the product entities representing the tens of thousands of products to be loaded into memory. For a sufficiently large retailer, this might not even be possible, given the amount of physical memory available on the machine.
Even if this was possible, it would probably cripple the performance of the site. Instead, we want only the categories to load. Only when the user drills down into the categories should a subset of the products in that category be loaded from the database.
To manage this problem, Hibernate provides a facility called lazy loading. When lazy loading is enabled, an entity’s associated entities will be loaded only when they are directly requested.
2. Lazy Loading in Action
We have understood the problem, let’s see how lazy loading actually helps with an example. If we consider solving the Category-product problem discussed above then we would be accessing a category in the below manner:
//Following code loads only a single category from the database: Category category = (Category) session.get(Category.class, new Integer(42));
However, if all products of this category are accessed, and lazy loading is in effect, the products are pulled from the database as needed. For instance, in the following snippet, the associated product objects will be loaded since it is explicitly referenced in the second line.
//Following code loads only a single category from the database Category category = (Category)session.get(Category.class, new Integer(42)); //This code will fetch all products for category 42 from database - "NOW" Set<Product> products = category.getProducts();
This solves our problem of loading the products only when they are needed.
3. The Default Behavior
Before moving further, it is important to recap the default behavior of lazy loading in the case of using hibernate mappings vs annotations.
The default behavior is to load ‘property values eagerly’ and to load ‘collections lazily’. Contrary to what you might remember if you have used plain Hibernate 2 (mapping files) before, where all references (including collections) are loaded eagerly by default.
- @OneToMany and @ManyToMany associations are defaulted to LAZY loading; and
- @OneToOne and @ManyToOne are defaulted to EAGER loading. This is important to remember to avoid any pitfall in future.
4. Enabling Lazy Loading in Hibernate
To enable lazy loading explicitly you must use “fetch = FetchType.LAZY” on an association that you want to lazy load when you are using hibernate annotations.
@OneToMany( mappedBy = "category", fetch = FetchType.LAZY ) private Set<ProductEntity> products;
Another attribute parallel to
"FetchType.EAGER" which is just opposite to LAZY i.e. it will load association entity as well when owner entity is fetched first time.
5. How Hibernate Applies Lazy Loading Behind the Scene
The simplest way that Hibernate can apply lazy load behavior upon the entities and associations is by providing a proxy implementation of them.
Hibernate intercepts calls to the entity by substituting a proxy for it derived from the entity’s class. Where the requested information is missing, it will be loaded from the database before control is ceded to the parent entity’s implementation.
Please note that when the association is represented as a collection class, then a wrapper (essentially a proxy for the collection, rather than for the entities that it contains) is created and substituted for the original collection.
When you access this collection proxy then what you get inside returned proxy collection are not proxy entities; rather they are actual entities.
To check if a lazy object has been initialized in hibernate, we can use following method call:
boolean success = Hibernate.isInitialized(products);
6. Effect of Lazy Loading on Detached Entities
As we know that hibernate can only access the database via a session, So If an entity is detached from the session and when we try to access an association (via a proxy or collection wrapper) that has not yet been loaded, Hibernate throws a
The solution is to ensure either that the entity is made persistent again by attaching it to a session or that all of the fields that will be required are accessed (so they are loaded into entity) before the entity is detached from the session.
That’s all for this simple, yet very important concept i.e. how to load lazy object in hibernate. This can be a question for beginners in hibernate fetching strategies interview questions.
Happy Learning !!