So far in previous tutorials, we have learned the concepts around entities persistence life cycle states, Some CRUD operations such as Save a hibernate entity, merge or refresh an entity and then we learned about cascading effect as well. Moving forward in this this tutorial, I will be discussing a must-known feature in hibernate, specially if you working in a very large application, known as lazy loading.
When Lazy Loading is Needed : Sample Problem
Consider one of common Internet web application: the online store. The store maintains a catalog of products. At the crudest level, this can be modeled as a catalog entity managing a series of product entities. In a large store, there may be tens of thousands of products grouped into various overlapping categories.
When a customer visits the store, the catalog must be loaded from the database. We probably don’t want the implementation to load every single one of the 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 were possible, it would probably cripple the performance of the site. Instead, we want only the catalog to load, possibly with the categories as well. 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 enabled, an entity’s associated entities will be loaded only when they are directly requested.
How Lazy Loading Solve the Problem
Now when we have understood the problem, let’s understand how lazy loading actually helps in real life. If we consider to solve the problem discussed above then we would be accessing a category (or catalog) in 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 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 solve our problem of loading the products only when they are needed.
How to Enable Lazy Loading in Hibernate
Before moving further, it is important to recap the default behavior of lazy loading in case of using hibernate mappings vs annotations.
Also note that
@ManyToMany associations are defaulted to LAZY loading; and
@ManyToOne are defaulted to EAGER loading. This is important to remember to avoid any pitfall in future.
To enable lazy loading explicitly you must use
"fetch = FetchType.LAZY" on a association which you want to lazy load when you are using hibernate annotations.
An example usage will look like this:
@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.
How Lazy Loading Works in Hibernate
The simplest way that Hibernate can apply lazy load behavior upon your 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. You need not to put much pressure on understanding this concept because on runtime it hardly matters.
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 cure 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 in Hibernate. Please drop a comment if something is not clear OR you want to discuss anything.
Happy Learning !!