Friday, 26 December 2014

Hibernate FetchType : Lazy Vs Eager


Hibernate provides the ability to either eagerly or lazily fetch associated entities. What it means, suppose you had Employee class and it contains collection of addresses associated with it.

class Employee{
        ....
        ....
        List<Address> addresses;
        .....
        .....
}

Lazy Fetch
When you access an employee object, the list of addresses associated with this employee object not fetched from database. The list of addresses fetched from database only if you ask them(using getter method). Lazy fetch is the default fetch strategy.

package myFirstHibernate;

import javax.persistence.Embeddable;

@Embeddable
public class Address {
  private String street;
  private String city;
  private String state;
  private String PIN;
  private String country;
  
  public String getStreet() {
    return street;
  }
  
  public void setStreet(String street) {
    this.street = street;
  }
  
  public String getCity() {
    return city;
  }
  
  public void setCity(String city) {
    this.city = city;
  }
  
  public String getState() {
    return state;
  }
  
  public void setState(String state) {
    this.state = state;
  }
  
  public String getPIN() {
    return PIN;
  }
  
  public void setPIN(String pIN) {
    PIN = pIN;
  }
  
  public String getCountry() {
    return country;
  }
  
  public void setCountry(String country) {
    this.country = country;
  }
  
}

package myFirstHibernate;

import java.util.List;

import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.JoinColumn;
import javax.persistence.Column;

import org.hibernate.annotations.CollectionId;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;

@Entity
public class Employee {
  @Id
  private int id;
  private String firstName;
  private String lastName;
  
  @ElementCollection
  @JoinTable(name="emp_addresses", joinColumns=@JoinColumn(name="emp_id"))
  List<Address> addresses;
  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public List<Address> getAddresses() {
    return addresses;
  }

  public void setAddresses(List<Address> addresses) {
    this.addresses = addresses;
  }
    
}


hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

  <session-factory>
  
    <!--  Database Connection settings -->
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.url">jdbc:mysql://localhost/sample</property>
    <property name="connection.username">root</property>
    <property name="connection.password">tiger</property>
    
    <!-- Enable the logging of all the generated SQL statements to the console -->
    <property name="show_sql">true</property>
    
    <!-- Format the generated SQL statement to make it more readable, -->
    <property name="format_sql">false</property>
    
    <!-- Hibernate will put comments inside all generated SQL statements to hint what’s the generated SQL trying to do -->
    <property name="use_sql_comments">false</property>
    
    <!-- This property makes Hibernate generate the appropriate SQL for the chosen database. -->
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    
    <!-- Drop and re-create the database schema on startup -->
    <property name="hbm2ddl.auto">create</property>
    
    <!-- mappings for annotated classes -->
    <mapping class="myFirstHibernate.Employee" />
    
  </session-factory>
  
</hibernate-configuration>

package myFirstHibernate;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

public class TestEmployee {
  
  /* Step 1: Create session factory */
  private static SessionFactory getSessionFactory() {
    Configuration configuration = new Configuration().configure();
    StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().
    applySettings(configuration.getProperties());
    SessionFactory factory = configuration.buildSessionFactory(builder.build());
        return factory;
    }
  
  public static void main(String args[]){
    Employee emp1 = new Employee();
    emp1.setId(1);
    emp1.setFirstName("Hari Krishna");
    emp1.setLastName("Gurram");
    
    Address addr1 = new Address();
    addr1.setCity("Bangalore");
    addr1.setCountry("India");
    addr1.setPIN("560037");
    addr1.setState("Karnataka");
    addr1.setStreet("Chowdeswari street");
      
    Address addr2 = new Address();
    addr2.setCity("Ongole");
    addr2.setCountry("India");
    addr2.setPIN("523169");
    addr2.setState("Andhra Pradesh");
    addr2.setStreet("Punuru");

    List<Address> addrList = new ArrayList<Address> ();
    addrList.add(addr1);
    addrList.add(addr2);
    
    emp1.setAddresses(addrList);
    
    /* To persisit data */
    SessionFactory sessionFactory = getSessionFactory();
    Session session = sessionFactory.openSession();
    session.beginTransaction();
    session.save(emp1);
    session.getTransaction().commit();
    session.close(); 
    
    Session session1 = sessionFactory.openSession();
    Employee emp2 = (Employee)session1.get(Employee.class, 1);
    System.out.println(emp2.getId() +" " + emp2.getFirstName() +" " + emp2.getLastName());
    System.out.println("Going to call list of addresses");
    List<Address> addr = emp2.getAddresses();
    Iterator<Address> iter = addr.iterator();
    while(iter.hasNext()){
      Address address = iter.next();
      System.out.println(address.getCity() +" " + address.getCountry() + " " + address.getPIN());
    }
    session1.close();  
  }
}


Run TestEmployee class, you will get output like below.
Hibernate: drop table if exists Employee
Hibernate: drop table if exists emp_addresses
Hibernate: create table Employee (id integer not null, firstName varchar(255), lastName varchar(255), primary key (id))
Hibernate: create table emp_addresses (emp_id integer not null, PIN varchar(255), city varchar(255), country varchar(255), state varchar(255), street varchar(255))
Hibernate: alter table emp_addresses add constraint FK_o3skpa21dhfq096yt91cm0x50 foreign key (emp_id) references Employee (id)
Dec 21, 2014 11:22:41 AM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
Hibernate: insert into Employee (firstName, lastName, id) values (?, ?, ?)
Hibernate: insert into emp_addresses (emp_id, PIN, city, country, state, street) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into emp_addresses (emp_id, PIN, city, country, state, street) values (?, ?, ?, ?, ?, ?)
Hibernate: select employee0_.id as id1_0_0_, employee0_.firstName as firstNam2_0_0_, employee0_.lastName as lastName3_0_0_ from Employee employee0_ where employee0_.id=?
1 Hari Krishna Gurram
Going to call list of addresses
Hibernate: select addresses0_.emp_id as emp_id1_0_0_, addresses0_.PIN as PIN2_1_0_, addresses0_.city as city3_1_0_, addresses0_.country as country4_1_0_, addresses0_.state as state5_1_0_, addresses0_.street as street6_1_0_ from emp_addresses addresses0_ where addresses0_.emp_id=?
Bangalore India 560037
Ongole India 523169


As you observe output, List of addresses are fetched from database after “Going to call list of addresses” statement executes. Addresses are fetched from database, only when you call getAddresses() method.

“List<Address> addr = emp2.getAddresses();”

Eager Loading
Eager loading loads all the relations associated with this entity at the time you accessing the object.

@ElementCollection(fetch=FetchType.EAGER)
@JoinTable(name="emp_addresses", joinColumns=@JoinColumn(name="emp_id"))
List<Address> addresses;

“FetchType.EAGER” specifies load this collection in eager mode.

package myFirstHibernate;

import java.util.List;

import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.JoinColumn;
import javax.persistence.Column;

import org.hibernate.annotations.CollectionId;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;

@Entity
public class Employee {
  @Id
  private int id;
  private String firstName;
  private String lastName;
  
  @ElementCollection(fetch=FetchType.EAGER)
  @JoinTable(name="emp_addresses", joinColumns=@JoinColumn(name="emp_id"))
  List<Address> addresses;
  
  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public String getLastName() {
    return lastName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public List<Address> getAddresses() {
    return addresses;
  }

  public void setAddresses(List<Address> addresses) {
    this.addresses = addresses;
  }
    
}


Re run “TestEmployee” class with updated “Employee” class, you will get output like below.

Hibernate: drop table if exists Employee
Hibernate: drop table if exists emp_addresses
Hibernate: create table Employee (id integer not null, firstName varchar(255), lastName varchar(255), primary key (id))
Hibernate: create table emp_addresses (emp_id integer not null, PIN varchar(255), city varchar(255), country varchar(255), state varchar(255), street varchar(255))
Hibernate: alter table emp_addresses add constraint FK_o3skpa21dhfq096yt91cm0x50 foreign key (emp_id) references Employee (id)
Dec 21, 2014 11:26:50 AM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
Hibernate: insert into Employee (firstName, lastName, id) values (?, ?, ?)
Hibernate: insert into emp_addresses (emp_id, PIN, city, country, state, street) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into emp_addresses (emp_id, PIN, city, country, state, street) values (?, ?, ?, ?, ?, ?)
Hibernate: select employee0_.id as id1_0_0_, employee0_.firstName as firstNam2_0_0_, employee0_.lastName as lastName3_0_0_, addresses1_.emp_id as emp_id1_0_1_, addresses1_.PIN as PIN2_1_1_, addresses1_.city as city3_1_1_, addresses1_.country as country4_1_1_, addresses1_.state as state5_1_1_, addresses1_.street as street6_1_1_ from Employee employee0_ left outer join emp_addresses addresses1_ on employee0_.id=addresses1_.emp_id where employee0_.id=?
1 Hari Krishna Gurram
Going to call list of addresses
Bangalore India 560037
Ongole India 523169


As you observe output, addresses are fetched at the time of fetching employee object itself.

Prevoius                                                 Next                                                 Home

No comments:

Post a Comment