Wednesday, 17 May 2017

Hibernate Lazy loading


Lazy loading loads the child objects on demand.

We have a parent and that parent has a collection of children. Using "lazy-load" concept, all children will not load while loading the parent. Instead, it loads them when requested to do so.

It is used to improve performance significantly since often you won't need the children and so they will not be loaded. Since Hibernate 3.0, lazy collection is enabled by default.

When Lazy Loading is needed: Sample Problem
Consider an online portal which maintains a catalog of products. This can be modeled as a catalog entity (Parent) managing a series of product entities (Children). 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 to Enable Lazy Loading in Hibernate
To enable lazy loading explicitly you must use "fetch = FetchType.LAZY" on an association which you want to lazy load when you are using hibernate annotations.

Lazy loading using Annotations
public class Category {

      @OneToMany(mappedBy = "category", fetch = FetchType.LAZY )
      private Set<ProductEntity> products;

      public Set<ProductEntity> getProducts() {
            return products;
      }
      public void setProducts(Set<ProductEntity> products) {
            this.products = products;
      }
}

Lazy loading using XML configuration
<set name="category" inverse="true" cascade="delete" lazy="false">
      <key column="category_id" />
            <one-to-many class="ProductEntity"/>
</set>

How Lazy Loading Works in Hibernate?
Hibernate uses a proxy object to support lazy loading. Basically, when you load data from tables, hibernate doesn’t load all the mapped objects. As soon as you reference a child or lookup object via getter methods, if the linked entity is not in the session cache, then the proxy code will go to the database and load the linked object. It uses javassist to effectively and dynamically generate sub-classed implementations of your entity objects.

Effect of Lazy Loading on Detached Entities
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 org.hibernate.LazyInitializationException: could not initialize proxy - no Session in Hibernate.

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.

Important point
We should also aware about n+1-problem.

Hibernate will not actually load all children when you access the collection. Instead, it will load each child individually. When iterating over the collection, this causes a query for every child. In order to avoid this, you can trick hibernate into loading all children simultaneously, e.g. by calling parent.getChildren().size().



No comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...