What Is Lazy Loading in Hibernate

when to use Lazy loading / Eager loading in hibernate?

I am trying to understand where to use lazy loading and where to use
eager loading, highly appreciate your insight.

Here are a few thoughts:

1) If you are going to always use something (for sure), you can eager load it.

2) Related to 1, if you are almost never going to use something, lazy load it.

3) Lazy loading tends to be more useful when large collections are involved.

4) Eagerly loading things will reduce session-related errors, at the potential cost of a performance hit.

5) For complicated data models and/or large databases, you are going to see how your app does under load an adjust your strategies.

6) It's difficult to get it right the first time. Do what feels right, and don't be afraid to change if necessary.

7) For large datasets, you are going to probably end up writing custom hql/queries anyway, where the default mappings can be overwritten, so lazy vs eager won't matter so much.

If you believe #6, then don't get stuck trying to plan too far ahead, and change it if you have to.

WRT your specific example, I would probably write a bunch of queries to access the data (driven by appropriate business needs, of course)

1) A query that loads the customer, and leaves the orders in the db (so lazy loading) that I would call when I need to get customer info

2) A query that loads the customer and all order info, for cases where I need it. So this case I'll ignore the default mapping.

With those two queries in place, in my service layers I have the tools I need to do what is correct based on the context of the situation.

What is the relationship between DTO and lazy-loading in Hibernate

Lazy loading is for entities, not DTOs.

A JPA entity can be represented as a POJO or a Proxy.

Using EntityManager.find gives you a POJO:

Post post = entityManager.find(Post.class, postId);

While the EtityManager.getReference method gives you a Proxy:

Post post = entityManager.getReference(Post.class, postId);

The POJO has its basic properties initialized because a SELECT statement was executed to fetch the entity. The Proxy does not hit the database upon creation. Only the id is set based on the provided entity identifier. Only you access the Proxy properties, a SELECT statement will be executed.

Proxies are also used for collections (e.g. @OneToMany or @ManyToMany) which are using the FetchType.LAZY strategy by default. Once you access the LAZY collection, a SELECT statement will be executed to fetch the associated collection.

Now, a DTO is based on a projection, hence a SELECT statement is executed prior to populating the DTO. For this purpose, you can say that the DTO is eagerly loaded every time.

DTOs are much more efficient than entities for read-only projections because you load just the table columns that you explicitly requested.

Lazy loading hibernate, the correct way and some doubts

If you don't want to get the error in first approach, you could use something like this:

Session miasession = HibernateUtil.getSessionFactory().getCurrentSession();

Invoice i = (Invoice) miasession.get(Invoice.class, id);

// load the collection before session is closed
model.addAttribute("subject", Hibernate.initialize(i.getSubject()));

Another way to solve lazy problems is to use OpenSessionInViewFilter in your web.xml

lazy initialization in hibernate

Lazy fetching (or initialization) is the opposite of eager fetching. Lazy fetching, the default in hibernate, means that when a record is loaded from the database, the one-to-many relationship child rows are not loaded. E.g.

@Entity
@Table(name = "COMPANY")
public class Company {
...
@OneToMany(fetch = FetchType.LAZY)
private Set<Employee> employees = new HashSet<Employee>();

requesting a company record will not return (set) Employees, who will have to be requested in another query.

Advantages

  • performance. Employees are only loaded when needed (and requested). Benefit on CPU, memory, bandwidth... (both Java side and SQL server side).

Drawbacks

  • when Employees are also needed, a separated query has to be performed.

Note that the query on Employees has to be performed during the same session (or the famous LazyInitializationException will be unwelcome).

This page holds interesting information.

Difference between FetchType LAZY and EAGER in Java Persistence API?

Sometimes you have two entities and there's a relationship between them. For example, you might have an entity called University and another entity called Student and a University might have many Students:

The University entity might have some basic properties such as id, name, address, etc. as well as a collection property called students that returns the list of students for a given university:

A university has many students

public class University {
private String id;
private String name;
private String address;
private List<Student> students;

// setters and getters
}

Now when you load a University from the database, JPA loads its id, name, and address fields for you. But you have two options for how students should be loaded:

  1. To load it together with the rest of the fields (i.e. eagerly), or
  2. To load it on-demand (i.e. lazily) when you call the university's getStudents() method.

When a university has many students it is not efficient to load all of its students together with it, especially when they are not needed and in suchlike cases you can declare that you want students to be loaded when they are actually needed. This is called lazy loading.

Here's an example, where students is explicitly marked to be loaded eagerly:

@Entity
public class University {

@Id
private String id;

private String name;

private String address;

@OneToMany(fetch = FetchType.EAGER)
private List<Student> students;

// etc.
}

And here's an example where students is explicitly marked to be loaded lazily:

@Entity
public class University {

@Id
private String id;

private String name;

private String address;

@OneToMany(fetch = FetchType.LAZY)
private List<Student> students;

// etc.
}

Lazy loading of @OneToOne relation with Hibernate

Try to understand it using @OneToMany relationship.

When you have that, you specify some collection i.e List, for example we have an entity

class A {
@OneToMany
List<B> bs;

public List<B> getBs() {
return bs;
}
}

So when hibernate loads the A, it is able to identify that you have List<B> and you may call getBs() just after the class is loaded so hibernate creates a wrapper list which doesn't have any B yet and it will wait until you perform any operation on the list ie. iterate, add etc.

As soon as you perform the operation, hibernate will issue the query and load the objects into the set, hence lazy loading works fine here.

That's why one-to-many by default is lazy

Now let's take example of @OneToOne

class A {
@OneToOne
B b;

public B getB() {}
}

When hibernate loads A, it will see that user may call the getB just after A is loaded, so it needs to initialise B as well.

Now, even if B supports proxy, hibernate have to initialise it with proxy or null and how that decision will be made, it will have to query the B to check if it exists or not but if it queries just to check, why just check only, why not initialise it fully, hence it does it eagerly, ignoring the Lazy attribute1

But this is not true for child side, if you specify the @One-To-One on child side

class B {
@OneToOne(lazy)
A a;

public A getA() {}
}

Because this is the entity for table which holds the foreign key to A entity table, hibernate will initialise it with the proxy of A because hibernate knows that this entity is child entity and has foreign key associated, so it can lazy load when required, if it's null, you would get null A.

Correction:

The above behaviour is obvious for the optionable relation (optional = true) as I have already explained and you may find other answers stating that, but it is not obvious when you use optional=false.

With non-optional relation, we would think that hibernate identify that there would be a child present for the parent so hibernate will initialise the proxy and it should depict the lazy loading behaviour.

But to even initialise the proxy, hibernate will need minimum information like identifier and it would need to query from the child table, hence it becomes the same case as optional relation and loads eagerly.

There is one solution to still make it work though (at least I thought so), that if you share the primary key of your parent entity with the child entity using @MapsId

class A {
@Id
private Integer id;

@OneToOne(fetch = Lazy, mappedBy = "a", optional = false)
private B b;
}

class B {
@Id
private Integer id;

@OneToOne
@MapsId
private A a;
}

This should have worked, because now you are sharing the parent primary key with the child and hibernate now knows the identifier and it doesn't need to query it from the table and should be able to initialise the proxy easily.

However, it doesn't work and still loads eagerly which is strange and after a little digging, I found this issue reported by Vlad himself.2

Although I found a workaround in related issues and have also asked on the above issue about it if that is a valid one, that's why not posting here.



1Some of the older version of hibernate does support the lazy loading from parent side as well but that behaviour is removed in recent versions because they needed to check the existence of the child.

2I checked this behaviour using hibernate version 5.4.8.Final and 5.4.30.Final



Related Topics



Leave a reply



Submit