Ленивая загрузка java hibernate

What is lazy loading in Hibernate?

What is lazy loading in Java? I don’t understand the process. Can anybody help me to understand the process of lazy loading?

14 Answers 14

Say you have a parent and that parent has a collection of children. Hibernate now can «lazy-load» the children, which means that it does not actually load all the children when loading the parent. Instead, it loads them when requested to do so. You can either request this explicitly or, and this is far more common, hibernate will load them automatically when you try to access a child.

Lazy-loading can help improve the performance significantly since often you won’t need the children and so they will not be loaded.

Also beware of the 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().

The statement «when you access the collection . it will load each child individually» is actually completely inaccurate. Its actually the exact opposite. Any dereference of parent.getChildren() will cause Hibernate to load all the children in the collection in one db query. Unless you used the very special «extra lazy» lazy loading hint. Or unless you cache the collection in second level cache and the associated children are not also cached.

«Lazy loading» means that an entity will be loaded only when you actually accesses the entity for the first time.

public Entity getEntity() < if (entity == null) < entity = loadEntity(); >return entity; > 

This saves the cost of preloading/prefilling all the entities in a large dataset beforehand while you after all actually don’t need all of them.

In Hibernate, you can configure to lazily load a collection of child entities. The actual lazy loading is then done inside the methods of the PersistentSet which Hibernate uses «under the hoods» to assign the collection of entities as Set .

public class Parent < private Setchildren; public Set getChildren() < return children; >> 
public void doSomething() < Setchildren = parent.getChildren(); // Still contains nothing. // Whenever you call one of the following (indirectly), // Hibernate will start to actually load and fill the set. children.size(); children.iterator(); > 

An object that doesn’t contain all of the data you need but knows how to get it.

So, when loading a given object, the idea is to not eager load the related object(s) that you may not use immediately to save the related performance cost. Instead, the related object(s) will be loaded only when used.

Читайте также:  Получить названия всех переменных python

This is not a pattern specific to data access and Hibernate but it is particularly useful in such fields and Hibernate supports lazy loading of one-to-many associations and single-point associations (one-to-one and many-to-one) also under certain conditions. Lazy interaction is discussed in more detail in Chapter 19 of the Hibernate 3.0 Reference Documentation.

Bydefault lazy loading is true.Lazy loading means when the select query is executed it will not hit the database. It will wait for getter function i.e when we required then ,it will fetch from the datbase. for example: You are a parent who has a kid with a lot of toys. But the current issue is whenever you call him (we assume you have a boy), he comes to you with all his toys as well. Now this is an issue since you do not want him carrying around his toys all the time. So being the rationale parent, you go right ahead and define the toys of the child as LAZY. Now whenever you call him, he just comes to you without his toys.

In layman’s language, it is like you are making a cake and you will need 5-10 ingredients from fridge. You have two options, get all ingredients from fridge and put it on your kitchen platform, or bring the item you want when you need.

Similarly, in eager loading, you fetch all information about bean and its related classes (not child or is-a relation but has a relationship, i.e. cake has flour, has milk, has cream etc), and in case of lazy loading, first you bring only its identifier and values that are coming from same table (necessary ingredients that first you will need in your bowl in case of cake). All information that is coming from other tables will be fetched as and when required/used.

Lazy fetching decides whether to load child objects while loading the Parent Object. You need to do this setting respective hibernate mapping file of the parent class. Lazy = true (means not to load child) 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.

Example : If you have a TABLE ? EMPLOYEE mapped to Employee object and contains set of Address objects. Parent Class : Employee class, Child class : Address Class

public class Employee < private Set address = new HashSet(); // contains set of child Address objects public Set getAddress () < return address; >public void setAddresss(Set address) < this. address = address; >> 

In the Employee.hbm.xml file

Читайте также:  Python datetime plus one day

In the above configuration. If lazy=»false» : — when you load the Employee object that time child object Address is also loaded and set to setAddresss() method. If you call employee.getAdress() then loaded data returns.No fresh database call.

If lazy=»true» :- This the default configuration. If you don?t mention then hibernate consider lazy=true. when you load the Employee object that time child object Adress is not loaded. You need extra call to data base to get address objects. If you call employee.getAdress() then that time database query fires and return results. Fresh database call.

Источник

Нетерпеливая/ленивая загрузка в спящем режиме

При работе с ORM выборку/загрузку данных можно разделить на два типа: нетерпеливую и ленивую.

В этом кратком руководстве мы собираемся указать на различия и показать, как мы можем использовать их в Hibernate.

2. Зависимости Maven

Чтобы использовать Hibernate, давайте сначала определим основную зависимость в нашем pom.xml :

 dependency>   groupId>org.hibernategroupId>   artifactId>hibernate-coreartifactId>   version>5.2.2.Finalversion>   dependency> 

Последнюю версию Hibernate можно найти здесь .

3. Нетерпеливая и ленивая загрузка

Первое, что мы должны обсудить здесь, это то, что такое отложенная загрузка и нетерпеливая загрузка:

  • Eager Loading — это шаблон проектирования, в котором инициализация данных происходит на месте.
  • Ленивая загрузка — это шаблон проектирования, который мы используем для отсрочки инициализации объекта до тех пор, пока это возможно.

Давайте посмотрим, как это работает.

Сначала мы рассмотрим класс UserLazy :

 @Entity   @Table(name = "USER")   public class UserLazy implements Serializable     @Id   @GeneratedValue   @Column(name = "USER_ID")   private Long userId;    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")   private SetOrderDetail> orderDetail = new HashSet();    // standard setters and getters   // also override equals and hashcode    > 

Далее мы увидим класс OrderDetail :

 @Entity   @Table (name = "USER_ORDER")   public class OrderDetail implements Serializable     @Id   @GeneratedValue   @Column(name="ORDER_ID")   private Long orderId;    @ManyToOne(fetch = FetchType.LAZY)   @JoinColumn(name="USER_ID")   private UserLazy user;    // standard setters and getters   // also override equals and hashcode    > 

У одного пользователя может быть несколько OrderDetails . В стратегии быстрой загрузки, если мы загружаем данные пользователя , он также загружает все связанные с ним заказы и сохраняет их в памяти.

Но когда мы включаем ленивую загрузку, если мы подтягиваем UserLazy , данные OrderDetail не будут инициализированы и загружены в память, пока мы не выполним явный вызов.

В следующем разделе мы увидим, как мы реализуем пример в Hibernate.

4. Загрузка конфигурации

Давайте посмотрим, как настроить стратегии выборки в Hibernate.

Мы можем включить отложенную загрузку, используя этот параметр аннотации:

Для Eager Fetching мы используем этот параметр:

Чтобы настроить Eager Loading, мы использовали класс -близнец UserLazy под названием UserEager .

В следующем разделе мы рассмотрим различия между двумя типами выборки.

5. Отличия

Как мы уже упоминали, основное различие между двумя типами выборки заключается в моменте загрузки данных в память.

 ListUserLazy> users = sessionLazy.createQuery("From UserLazy").list();   UserLazy userLazyLoaded = users.get(3);   return (userLazyLoaded.getOrderDetail()); 

При ленивой инициализации orderDetailSet будет инициализирован только тогда, когда мы явно вызовем его, используя геттер или какой-либо другой метод:

 UserLazy userLazyLoaded = users.get(3); 

Но при нетерпеливом подходе в UserEager он будет инициализирован сразу в первой строке:

 ListUserEager> user = sessionEager.createQuery("From UserEager").list(); 

Для ленивой загрузки мы используем прокси-объект и запускаем отдельный SQL-запрос для загрузки orderDetailSet .

Идея отключения прокси или отложенной загрузки считается плохой практикой в Hibernate. Это может привести к извлечению и хранению большого количества данных, независимо от необходимости в этом.

Мы можем использовать следующий метод для проверки функциональности:

 Hibernate.isInitialized(orderDetailSet); 

Теперь давайте посмотрим на запросы, сгенерированные в любом случае:

 property name="show_sql">trueproperty> 

Приведенный выше параметр в файле fetching.hbm.xml показывает сгенерированные запросы SQL. Если мы посмотрим на вывод консоли, мы увидим сгенерированные запросы.

Для отложенной загрузки вот запрос, сгенерированный для загрузки данных пользователя :

 select user0_.USER_ID as USER_ID1_0_, ... from USER user0_ 

Однако при нетерпеливой загрузке мы увидели соединение с USER_ORDER :

 select orderdetai0_.USER_ID as USER_ID4_0_0_, orderdetai0_.ORDER_ID as ORDER_ID1_1_0_, orderdetai0_ ...   from USER_ORDER orderdetai0_ where orderdetai0_.USER_ID=? 

Приведенный выше запрос генерируется для всех пользователей , что приводит к гораздо большему использованию памяти, чем при другом подходе.

6. Преимущества и недостатки

6.1. Ленивая загрузка

  • Гораздо меньшее время начальной загрузки, чем в другом подходе
  • Меньшее потребление памяти, чем в другом подходе
  • Отложенная инициализация может повлиять на производительность в нежелательные моменты.
  • В некоторых случаях нам нужно обращаться с лениво инициализированными объектами с особой осторожностью, иначе мы можем получить исключение.

6.2. Нетерпеливая загрузка

  • Долгое время первоначальной загрузки
  • Загрузка слишком большого количества ненужных данных может повлиять на производительность

7. Ленивая загрузка в спящем режиме

Hibernate применяет ленивую загрузку сущностей и ассоциаций, предоставляя прокси-реализацию классов.

Hibernate перехватывает вызовы объекта, заменяя его прокси-сервером, полученным из класса объекта. В нашем примере отсутствующая запрошенная информация будет загружена из базы данных до того, как управление будет передано реализации класса User .

Следует также отметить, что когда ассоциация представлена как класс коллекции (в приведенных выше примерах она представлена как Set orderDetailSet ), создается оболочка и заменяется исходной коллекцией.

Чтобы узнать больше о шаблоне проектирования прокси, обратитесь сюда .

8. Заключение

В этой статье мы показали примеры двух основных типов выборки, используемых в Hibernate.

Для получения дополнительной информации посетите официальный сайт Hibernate.

Чтобы получить код, обсуждаемый в этой статье, загляните в этот репозиторий .

Источник

Оцените статью