Hibernate Proxy Object:
If you want retrieve user object from the database, so what field value are retrieved from the database and which field are initialized. Suppose one user XYZ has the 100 addresses in the database and we want to retrieved the name of this user from database. For that we retrieve the user object, now question is this what about the field listOfAddress field, Is it also have the value? if you say yes so what about cost of memory ? if you say no so how to retrieve the value associated with that field the address table in the database on demand.
-A | *---B | | | *---C | | | *---D | | | *---E | | | *---F | | | *---G *---H
Ok lets see in the given below flow of the diagram.
In Hibernate 2 does not proxy objects by default. However, experience has shown that using object proxies is preferred, so this is the default in Hibernate 3.
user.getListOfAddress(); —>> this return the list of the address associated with that particular user which name is XYZ this is the default behavior of the Hibernate 3.
LAZY = fetch when needed EAGER = fetch immediately
1. Lazy Fetch Type: This the default fetch type of the hibernate 3.
Now when you load a User from the database, JPA loads its id, name, and address fields for you. But you have two options for users: to load it together with the rest of the fields (i.e. eagerly) or to load it on-demand (i.e. lazily) when you call the user’s getListOfAddresses() method.
Lazy/Select Fetch strategy:- Select Fetch strategy is the lazy fetching of associations. The purpose of Lazy strategy is memory optimization . When I say memory optimization it means it means it saves us from heap error. This is what I think. So we can say yes if we are loading too objects in aseesion we should go for Lazy Fetch strategy but in terms of time performance it does not provide any Benefit. Agreed?
When a user has many addresses it is not efficient to load all of its addresses with it when they are not needed. So in suchlike cases, you can declare that you want addresses to be loaded when they are actually needed. This is called lazy loading.
package com.sdnext.hibernate.tutorial.dto;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Table;
@Entity
@Table (name=”USER_DETAIL”)
public class UserDetails
{
@Id
@Column(name=”USER_ID”)
@GeneratedValue(strategy=GenerationType.AUTO)
private int userId;
@Column(name=”USER_NAME”)
private String userName;
@ElementCollection(fetch=FetchType.LAZY)
@JoinTable(name=”USER_ADDRESS”, joinColumns=@JoinColumn(name=”USER_ID”))
private Collection<Address> lisOfAddresses = new ArrayList<Address>();
public Collection<Address> getLisOfAddresses() {
return lisOfAddresses;
}
public void setLisOfAddresses(Collection<Address> lisOfAddresses) {
this.lisOfAddresses = lisOfAddresses;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String toString()
{
return “[User Name: “+userName+”n Office Address: “+lisOfAddresses+”]”;
}
}
package com.sdnext.hibernate.tutorial;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import com.sdnext.hibernate.tutorial.dto.Address;
import com.sdnext.hibernate.tutorial.dto.UserDetails;
public class HibernateTestDemo {
/**
* @param args
*/
public static void main(String[] args)
{
UserDetails user = new UserDetails(); // create user object
//user.setUserId(1);
user.setUserName(“Dinesh Rajput”);
Address address1 = new Address(); // create address object
address1.setStreet(“First Street”);
address1.setCity(“First City”);
address1.setState(“First State”);
address1.setPincode(“First Pin”);
Address address2 = new Address(); // create another address object
address2.setStreet(“Second Street”);
address2.setCity(“Second City”);
address2.setState(“Second State”);
address2.setPincode(“Second Pin”);
user.getLisOfAddresses().add(address1); // set the addresses objects to list of the addresses
user.getLisOfAddresses().add(address2);
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory(); // create session factory object
Session session = sessionFactory.openSession(); // create session object
session.beginTransaction(); // start transaction object
session.save(user); // save the user to database
session.getTransaction().commit(); // commit the transaction
session.close(); // closing session
session = sessionFactory.openSession(); // again create another session object
user = null;
user = (UserDetails) session.get(UserDetails.class, 1); // retrieved the user from the database for particular user which user id = 2 this object it is proxy user object.
System.out.println(user.getLisOfAddresses().size());
}
}
******************************************************************************
OUTPUT:Look care fully the output has the two select query one is for user and another is for address table when we call getListOfAddresses();
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotations.Version).
log4j:WARN Please initialize the log4j system properly.
Hibernate: insert into USER_DETAIL (USER_NAME) values (?)
Hibernate: insert into USER_ADDRESS (USER_ID, CITY_NAME, PIN_CODE, STATE_NAME, STREET_NAME) values (?, ?, ?, ?, ?)
Hibernate: insert into USER_ADDRESS (USER_ID, CITY_NAME, PIN_CODE, STATE_NAME, STREET_NAME) values (?, ?, ?, ?, ?)
Hibernate: select userdetail0_.USER_ID as USER1_0_0_, userdetail0_.USER_NAME as USER2_0_0_ from USER_DETAIL userdetail0_ where userdetail0_.USER_ID=?
Hibernate: select lisofaddre0_.USER_ID as USER1_0_, lisofaddre0_.CITY_NAME as CITY2_0_, lisofaddre0_.PIN_CODE as PIN3_0_, lisofaddre0_.STATE_NAME as STATE4_0_, lisofaddre0_.STREET_NAME as STREET5_0_ from USER_ADDRESS lisofaddre0_ where lisofaddre0_.USER_ID=?
2
******************************************************************************
Now if you change to some lines of code for this class file to verify the PROXY object.
Before calling getListOfAddresses() method close the session then look what happens.
session = sessionFactory.openSession(); // again create another session object
user = null;
user = (UserDetails) session.get(UserDetails.class, 1); // retrieved the user from the database for particular user which user id = 2 this object it is proxy user object.
session.close(); // close the session before calling collection getter
System.out.println(user.getLisOfAddresses().size());
Now Output:
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotations.Version).
log4j:WARN Please initialize the log4j system properly.
Hibernate: insert into USER_DETAIL (USER_NAME) values (?)
Hibernate: insert into USER_ADDRESS (USER_ID, CITY_NAME, PIN_CODE, STATE_NAME, STREET_NAME) values (?, ?, ?, ?, ?)
Hibernate: insert into USER_ADDRESS (USER_ID, CITY_NAME, PIN_CODE, STATE_NAME, STREET_NAME) values (?, ?, ?, ?, ?)
Hibernate: select userdetail0_.USER_ID as USER1_0_0_, userdetail0_.USER_NAME as USER2_0_0_ from USER_DETAIL userdetail0_ where userdetail0_.USER_ID=?
Exception in thread “main” org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.sdnext.hibernate.tutorial.dto.UserDetails.lisOfAddresses, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException
(AbstractPersistentCollection.java:380)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected
(AbstractPersistentCollection.java:372)
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:119)
at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248)
at com.sdnext.hibernate.tutorial.HibernateTestDemo.main(HibernateTestDemo.java:48)
******************************************************************************
As above code failed run because when we are using the LAZY Type strategy of fetching an object hibernate session return the proxy object, it exist in the session if we are closing the session the lazy loading is not happening.
2. Eager Fetch Strategy:
In hibernate 2 this is default behavior of the to retrieving an object from the database.
Eager/Join Fetch strategy:- Join Fetch strategy the eager fetching of associations.The purpose of Join Fetch strategy is optimization in terms of time.I mean even associations are fetched right at the time of fetching parent object. So in this case we don’t make database call again and again . So this will be much faster.Agreed that this will bad if we are fetching too many objects in a session because we can get java heap error.
Now we look on the code for EAGER LOADING.
UserDetais.java
package com.sdnext.hibernate.tutorial.dto;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Table;
@Entity
@Table (name=”USER_DETAIL”)
public class UserDetails
{
@Id
@Column(name=”USER_ID”)
@GeneratedValue(strategy=GenerationType.AUTO)
private int userId;
@Column(name=”USER_NAME”)
private String userName;
@ElementCollection(fetch=FetchType.EAGER)
@JoinTable(name=”USER_ADDRESS”, joinColumns=@JoinColumn(name=”USER_ID”))
private Collection<Address> lisOfAddresses = new ArrayList<Address>();
public Collection<Address> getLisOfAddresses() {
return lisOfAddresses;
}
public void setLisOfAddresses(Collection<Address> lisOfAddresses) {
this.lisOfAddresses = lisOfAddresses;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String toString()
{
return “[User Name: “+userName+”n Office Address: “+lisOfAddresses+”]”;
}
}
Now run the following code and see the output—
package com.sdnext.hibernate.tutorial;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import com.sdnext.hibernate.tutorial.dto.Address;
import com.sdnext.hibernate.tutorial.dto.UserDetails;
public class HibernateTestDemo {
/**
* @param args
*/
public static void main(String[] args)
{
UserDetails user = new UserDetails();
//user.setUserId(1);
user.setUserName(“Dinesh Rajput”);
Address address1 = new Address();
address1.setStreet(“First Street”);
address1.setCity(“First City”);
address1.setState(“First State”);
address1.setPincode(“First Pin”);
Address address2 = new Address();
address2.setStreet(“Second Street”);
address2.setCity(“Second City”);
address2.setState(“Second State”);
address2.setPincode(“Second Pin”);
user.getLisOfAddresses().add(address1);
user.getLisOfAddresses().add(address2);
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(user);
session.getTransaction().commit();
session.close();
session = sessionFactory.openSession();
user = null;
user = (UserDetails) session.get(UserDetails.class, 1);
session.close(); //closing the session before calling collection getter
System.out.println(user.getLisOfAddresses().size());
}
}
OUTPUT:
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotations.Version).
log4j:WARN Please initialize the log4j system properly.
Hibernate: insert into USER_DETAIL (USER_NAME) values (?)
Hibernate: insert into USER_ADDRESS (USER_ID, CITY_NAME, PIN_CODE, STATE_NAME, STREET_NAME) values (?, ?, ?, ?, ?)
Hibernate: insert into USER_ADDRESS (USER_ID, CITY_NAME, PIN_CODE, STATE_NAME, STREET_NAME) values (?, ?, ?, ?, ?)
Hibernate: select userdetail0_.USER_ID as USER1_0_0_, userdetail0_.USER_NAME as USER2_0_0_, lisofaddre1_.USER_ID as USER1_2_, lisofaddre1_.CITY_NAME as CITY2_2_, lisofaddre1_.PIN_CODE as PIN3_2_, lisofaddre1_.STATE_NAME as STATE4_2_, lisofaddre1_.STREET_NAME as STREET5_2_ from USER_DETAIL userdetail0_ left outer join USER_ADDRESS lisofaddre1_ on userdetail0_.USER_ID=lisofaddre1_.USER_ID where userdetail0_.USER_ID=?
2******************************************************************************
See this is successfully run the code because we are using the EAGER fetching strategy so in this strategy session return the original object with all field are initialized when load on the memory.
In the above output string look care fully there are only one select statement with join clause.
So now can we say in the hibernate session where we are not loading too many objects we should go for Eager fetch as it will be much better in terms of time response(Any ways memory will be reclaimed by garbage collector once we close the session).
In Next Chapter we will discuss about One to One Mapping.
<<Previous Chapter 15<< >>Next Chapter17>>
Great Explanation. Thank you
I dont understand with the outcome of lazy loading. At the end both lazy and eager did the same. lazy fired 2 queries, Eager fired 1 query. Suppose if i want that data in the UI, which to use and can anybody pls discuss?.
Wonderful points you have mentioned here, I will be sure to
bookmark your blog and may come back in the future. thank you for sharing