Lazy setting decides whether to load child objects while loading the Parent Object. You need to specify parent class.Lazy = true in hibernate mapping file. By default the lazy loading of the child objects is true. This make sure that the child objects are not loaded unless they are explicitly invoked in the application by calling getChild() method on parent. In this case hibernate issues a fresh database call to load the child when getChild() is actully called on the Parent object. But in some cases you do need to load the child objects when parent is loaded. Just make the lazy=false and hibernate will load the child when parent is loaded from the database.
Examples: Address child of User class can be made lazy if it is not required frequently. But you may need to load the Author object for Book parent whenever you deal with the book for online bookshop.
Hibernate does not support lazy initialization for detached objects. Access to a lazy association outside of the context of an open Hibernate session will result in an exception.
The annotations can be directly put onto the fields or on the corresponding getter methods. In the following example we use the fields:
import javax.persistence.* @Entity
public class Person { @Id @GeneratedValue
private long id; private String name; public String getId() {
return this.id;
} public String getName() {
return this.name;
}
}
Anyways, putting the annotations to the fields has a painful – although non obvious – side effect in connection with hibernate proxies created by lazy loading.
Let’s have a look at the following example of a 1:1 relationship (constructors have been omitted to keep the code short):
@Entity
public class Person { @Id @GeneratedValue
private long id; private String name; @OneToOne(fetch = FetchType.LAZY)
private Address address; public String getId() {
return this.id;
} public String getName() {
return this.name;
}
} @Entity
public class Address {
@Id @GeneratedValue
private long id; private String town; public long getId() {
return this.id;
} public String getTown() {
return this.town;
}
}
If we now load a Person
object in a Hibernate session, then the Address
is not loaded initially (due to the FetchType.LAZY
); Hibernate creates a proxy for it:
Person person = (Person) session.load(Person.class, Long.valueOf(1));
Address address = person.getAddress(); // Hibernate returns a proxy here
Those Hibernate proxies access the database as soon as the field is first accessed:
String town = address.getTown(); // implicit db access by Hibernate
This is true for all fields except the identifier property (the field with the @Id
Annotation) as this value is already fetched with the SELECT
on the table Person
.
long addressId = address.getId();
And that’s the trap: Although we only access the ID, Hibernate initializes the Proxy and fetches the whole record. The reason is that Hibernate doesn’t know anything about the methodgetId()
if the @Id
-Annotation is placed on the field. Hibernate therefore thinks that getId()
is a standard field access and loads the whole record. If you access that field outside the Hibernate session, you therefore get a LazyInitializationException
.
To fix that problem, the @Id
annotation needs to be put to the getter method. That in turn makes it necessary to put all other annotations to the getters as Hibernate does not allow to mix field and getter annoations. And as we’re now using getters for our annotations, we also need to provide setters as well (those can be private
or protected
).
Our code now looks as follows:
@Entity
public class Person { private long id;
private String name;
private Address address; @Id @GeneratedValue
public String getId() {
return this.id;
} public String getName() {
return this.name;
} @OneToOne(fetch = FetchType.LAZY)
public Address getAddress() {
return this.address;
}
} @Entity
public class Address {
private long id; private String town; @Id @GeneratedValue
public long getId() {
return this.id;
} public String getTown() {
return this.town;
}
}
Lazy loading is working as expected:
Person person = (Person) session.load(Person.class, Long.valueOf(1));
Address address = person.getAddress();
long addressId = address.getId(); // no DB-Select
String town = address.getTown(); // Proxy gets initialized, DB-Select
Like this:
Like Loading...