Różnica między FETCHTYPE LAZY i EAGER w Java Persistence API?

Jestem nowicjuszem Java Persistence API i Hibernate.

Jaka jest różnica między FetchType.LAZY oraz FetchType.EAGER W Java Persistence API?

Author: Jaumzera, 2010-06-07

15 answers

Czasami masz dwa byty i istnieje między nimi związek. Na przykład możesz mieć podmiot o nazwie University i inny podmiot o nazwie Student, A Uniwersytet może mieć wielu studentów:

Jednostka Uniwersytecka może mieć pewne podstawowe właściwości, takie jak identyfikator, nazwa, adres itp. jak również właściwość collection o nazwie students, która zwraca listę studentów dla danej uczelni:

Uniwersytet ma wielu studentów

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

   // setters and getters
}

Teraz, gdy załadujesz Uniwersytet z baza danych, JPA ładuje swoje pola id, nazwa i adres dla Ciebie. Ale masz dwie opcje, jak uczniowie powinni być ładowani:

  1. aby załadować go razem z resztą pól (np.]}
  2. , aby załadować go na żądanie (tzn. leniwie), gdy wywołasz metodę Uniwersytetu getStudents().

Gdy uczelnia ma wielu studentów, nie jest wydajne ładowanie wszystkich swoich studentów razem z nim, zwłaszcza gdy nie są one potrzebne i w takich przypadkach można zadeklarować że chcesz, aby uczniowie byli ładowani, gdy są rzeczywiście potrzebne. To się nazywa leniwe Ładowanie.

Oto przykład, gdzie {[6] } jest wyraźnie zaznaczone do załadowania:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

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

    // etc.    
}

A oto przykład gdzie students jest wyraźnie zaznaczone do załadowania leniwie:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

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

    // etc.
}
 1138
Author: βξhrαng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-03 10:28:12

Zasadniczo,

LAZY = fetch when needed
EAGER = fetch immediately
 299
Author: unbeli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-14 20:07:52

EAGER wczytywanie kolekcji oznacza, że są one pobierane w całości w momencie pobierania ich rodzica. Więc jeśli masz Course i ma List<Student>, wszyscy uczniowie są pobierani z bazy danych w czasie pobierania Course.

LAZY z drugiej strony oznacza to, że zawartość List jest pobierana tylko wtedy, gdy próbujesz uzyskać do nich dostęp. Na przykład przez wywołanie course.getStudents().iterator(). Wywołanie dowolnej metody dostępu w List zainicjuje wywołanie do bazy danych w celu pobrania elementów. To jest zaimplementowany przez utworzenie Proxy wokół List (lub Set). Więc dla Twoich leniwych zbiorów, konkretne typy to nie ArrayList i HashSet, Ale PersistentSet i PersistentList (lub PersistentBag)

 68
Author: Bozho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-07 15:54:39

Mogę rozważyć wydajność i wykorzystanie pamięci. Jedną dużą różnicą jest to, że strategia EAGER fetch pozwala na użycie pobranego obiektu danych bez sesji. Dlaczego?
Wszystkie dane są pobierane, gdy niecierpliwie zaznaczone dane w obiekcie, gdy sesja jest podłączona. Jednak w przypadku strategii lazy loading, lazy loading marked object nie pobiera danych, jeśli sesja jest odłączona (po instrukcji session.close()). Wszystko to może być wykonane przez hibernate proxy. Eager strategy pozwala na dostęp do danych po zamknięciu sesja.

 17
Author: Kyung Hwan Min,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-16 11:18:23

Według mojej wiedzy oba rodzaje aportów zależą od twoich wymagań.

FetchType.LAZY jest na żądanie (tj. kiedy wymagaliśmy danych).

FetchType.EAGER jest natychmiastowe (tzn. zanim pojawi się nasz wymóg, niepotrzebnie pobieramy rekord)

 11
Author: JDGuide,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-11 12:20:53

Domyślnie dla wszystkich obiektów collection i map regułą pobierania jest FetchType.LAZY, a dla innych instancji jest ona zgodna z zasadą FetchType.EAGER.
W skrócie, relacje @OneToMany i @ManyToMany nie pobierają powiązanych obiektów (kolekcji i map) implicicly, ale operacja pobierania jest kaskadowa przez pole w @OneToOne i @ManyToOne.

(Dzięki uprzejmości: - objectdbcom)

 11
Author: babai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-16 11:19:27

Zarówno FetchType.LAZY jak i FetchType.EAGER są używane do definiowania domyślnego planu pobierania.

Niestety, możesz zastąpić domyślny plan pobierania tylko dla leniwego pobierania. Chętne pobieranie jest mniej elastyczne i może prowadzić do wielu problemów z wydajnością.

Moja rada polega na ograniczeniu pragnienia wzbudzania Twoich skojarzeń, ponieważ pobieranie jest obowiązkiem czasu zapytań. Tak więc wszystkie Twoje zapytania powinny używać dyrektywy fetch , aby pobrać tylko to, co jest niezbędne dla bieżącego przypadku biznesowego.

 10
Author: Vlad Mihalcea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-09 16:18:06

Typ pobierania Lazy jest domyślnie wybierany przez Hibernate, chyba że wyraźnie zaznaczono typ pobierania Eager. Aby być bardziej dokładnym i zwięzłym, różnicę można określić jak poniżej.

FetchType.LAZY = to nie ładuje relacji, chyba że wywołasz je za pomocą metody getter.

FetchType.EAGER = to obciąża wszystkie związki.

Plusy i minusy tych dwóch typów pobierania.

Lazy initialization poprawia wydajność poprzez unikanie niepotrzebnych obliczeń i redukcję pamięci wymagania.

Eager initialization wymaga większego zużycia pamięci, a szybkość przetwarzania jest powolna.

Powiedziawszy to, zależy od sytuacji każda z tych inicjalizacji może być użyta.

 7
Author: Dulith De Costa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-14 14:24:18

Z Javadoc :

EAGER strategy jest wymogiem w środowisku runtime dostawcy persistence, że dane muszą być chętnie pobierane. Strategia leniwa jest wskazówką dla środowiska wykonawczego dostawcy persistence, że dane powinny być pobierane leniwie, gdy są po raz pierwszy dostępne.

Np. eager jest bardziej proaktywny niż leniwy. Leniwe dzieje się tylko przy pierwszym użyciu (jeśli dostawca weźmie podpowiedź), podczas gdy z chętnych rzeczy (może) dostać wstępnie pobrane.

 6
Author: T.J. Crowder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-07 15:31:35

Główną różnicą między tymi dwoma typami pobierania jest moment, w którym dane są ładowane do pamięci.
Załączyłem 2 zdjęcia, które pomogą Ci to zrozumieć.

Eager fetch
Chętny aport

Leniwy aport Leniwy aport

 5
Author: Ali Yeganeh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-21 19:43:30

Książka.java

        import java.io.Serializable;
        import javax.persistence.Column;
        import javax.persistence.Entity;
        import javax.persistence.GeneratedValue;
        import javax.persistence.GenerationType;
        import javax.persistence.Id;
        import javax.persistence.ManyToOne;
        import javax.persistence.Table;

        @Entity
        @Table(name="Books")
        public class Books implements Serializable{

        private static final long serialVersionUID = 1L;
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @Column(name="book_id")
        private int id;
        @Column(name="book_name")
        private String name;

        @Column(name="author_name")
        private String authorName;

        @ManyToOne
        Subject subject;

        public Subject getSubject() {
            return subject;
        }
        public void setSubject(Subject subject) {
            this.subject = subject;
        }

        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getAuthorName() {
            return authorName;
        }
        public void setAuthorName(String authorName) {
            this.authorName = authorName;
        }

        }

temat.java

    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue; 
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.OneToMany;
    import javax.persistence.Table;

    @Entity
    @Table(name="Subject")
    public class Subject implements Serializable{

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="subject_id")
    private int id;
    @Column(name="subject_name")
    private String name;
    /**
    Observe carefully i have mentioned fetchType.EAGER. By default its is fetchType.LAZY for @OneToMany i have mentioned it but not required. Check the Output by changing it to fetchType.EAGER
    */

    @OneToMany(mappedBy="subject",cascade=CascadeType.ALL,fetch=FetchType.LAZY,
orphanRemoval=true)
    List<Books> listBooks=new ArrayList<Books>();

    public List<Books> getListBooks() {
        return listBooks;
    }
    public void setListBooks(List<Books> listBooks) {
        this.listBooks = listBooks;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    }

HibernateUtil.java

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {

 private static SessionFactory sessionFactory ;
 static {
    Configuration configuration = new Configuration();
    configuration.addAnnotatedClass (Com.OneToMany.Books.class);
    configuration.addAnnotatedClass (Com.OneToMany.Subject.class);
    configuration.setProperty("connection.driver_class","com.mysql.jdbc.Driver");
    configuration.setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/hibernate");                                
    configuration.setProperty("hibernate.connection.username", "root");     
    configuration.setProperty("hibernate.connection.password", "root");
    configuration.setProperty("dialect", "org.hibernate.dialect.MySQLDialect");
    configuration.setProperty("hibernate.hbm2ddl.auto", "update");
    configuration.setProperty("hibernate.show_sql", "true");
    configuration.setProperty(" hibernate.connection.pool_size", "10");
    configuration.setProperty(" hibernate.cache.use_second_level_cache", "true");
    configuration.setProperty(" hibernate.cache.use_query_cache", "true");
    configuration.setProperty(" cache.provider_class", "org.hibernate.cache.EhCacheProvider");
    configuration.setProperty("hibernate.cache.region.factory_class" ,"org.hibernate.cache.ehcache.EhCacheRegionFactory");

   // configuration
    StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
    sessionFactory = configuration.buildSessionFactory(builder.build());
 }
public static SessionFactory getSessionFactory() {
    return sessionFactory;
}
} 

Main.java

    import org.hibernate.Session;
    import org.hibernate.SessionFactory;

    public class Main {

    public static void main(String[] args) {
        SessionFactory factory=HibernateUtil.getSessionFactory();
        save(factory);
        retrieve(factory);

    }

     private static void retrieve(SessionFactory factory) {
        Session session=factory.openSession();
        try{
            session.getTransaction().begin();
            Subject subject=(Subject)session.get(Subject.class, 1);
            System.out.println("subject associated collection is loading lazily as @OneToMany is lazy loaded");

            Books books=(Books)session.get(Books.class, 1);
            System.out.println("books associated collection is loading eagerly as by default @ManyToOne is Eagerly loaded");
            /*Books b1=(Books)session.get(Books.class, new Integer(1));

            Subject sub=session.get(Subject.class, 1);
            sub.getListBooks().remove(b1);
            session.save(sub);
            session.getTransaction().commit();*/
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            session.close();
        }

        }

       private static void save(SessionFactory factory){
        Subject subject=new Subject();
        subject.setName("C++");

        Books books=new Books();
        books.setAuthorName("Bala");
        books.setName("C++ Book");
        books.setSubject(subject);

        subject.getListBooks().add(books);
        Session session=factory.openSession();
        try{
        session.beginTransaction();

        session.save(subject);

        session.getTransaction().commit();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            session.close();
        }
    }

    }

Sprawdź metodę retrieve () Main.java. Gdy otrzymamy Subject, to jego zbiór listBooks, oznaczony @OneToMany, zostanie ładowany leniwie. Ale z drugiej strony, książki związane ze zbiorem temat , opatrzony adnotacją @ManyToOne, loads eargerly (by [default][1] for @ManyToOne, fetchType=EAGER). Możemy zmienić zachowanie umieszczając fetchType.EAGER on @OneToMany Subject.java lub fetchType.LAZY on @ManyToOne in Books.java.

 3
Author: Deepak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-27 19:31:20

Chcę dodać tę notkę do tego, co zostało powiedziane powyżej.

Załóżmy, że używasz odpoczynku wiosennego z tym prostym architektem:

Controller Service Repozytorium

I chcesz zwrócić niektóre dane do front-endu, jeśli używasz FetchType.LAZY, otrzymasz wyjątek po zwróceniu danych do metody kontrolera, ponieważ sesja jest zamknięta w usłudze, więc JSON Mapper Object nie może pobrać danych.

Istnieją trzy wspólne opcje rozwiązania tego problemu, zależy od projekt, wykonanie i twórca:

  1. najłatwiej jest użyć FetchType.EAGER, aby sesja nadal żyła przy metodzie kontrolera, ale ta metoda wpłynie na wydajność.
  2. anty-patterns rozwiązania, aby sesja trwała do końca wykonania, jest to ogromny problem wydajności w systemie.
  3. najlepszą praktyką jest użycie FetchType.LAZY z maperem podobnym do MapStruct do przeniesienia danych z Entity do innego obiektu danych DTO, a następnie odesłanie go z powrotem do kontrolera, więc nie ma wyjątku, jeśli sesja zostanie zamknięta.
 2
Author: Ebraheem Alrabeea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-07 10:00:26

Public enum FetchType rozszerza Javę.lang.Enum Definiuje strategie pobierania danych z bazy danych. EAGER strategy jest wymogiem w środowisku runtime dostawcy persistence, że dane muszą być chętnie pobierane. Strategia leniwa jest wskazówką dla środowiska wykonawczego dostawcy persistence, że dane powinny być pobierane leniwie, gdy są po raz pierwszy dostępne. Implementacja może pobierać dane, dla których podano podpowiedź strategii leniwej. Przykład: @ Basic (fetch=LAZY) protected String getName () {return name;}

Źródło

 1
Author: Anas Lachheb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-29 16:10:20

@drop-shadow jeśli używasz Hibernate, możesz wywołać {[1] } po wywołaniu metody getStudents():

Public class UniversityDaoImpl extends GenericDaoHibernate<University, Integer> implements UniversityDao {
    //...
    @Override
    public University get(final Integer id) {
        Query query = getQuery("from University u where idUniversity=:id").setParameter("id", id).setMaxResults(1).setFetchSize(1);
        University university = (University) query.uniqueResult();
        ***Hibernate.initialize(university.getStudents());***
        return university;
    }
    //...
}
 0
Author: Jules0707,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-16 11:21:25

LAZY: pobiera encje potomne leniwie, tzn. w czasie pobierania encji rodzica po prostu pobiera proxy (utworzone przez cglib lub inne narzędzie) encji potomnych, a gdy uzyskasz dostęp do dowolnej właściwości encji potomnej, jest ona faktycznie pobierana przez hibernate.

EAGER: pobiera byty dziecka wraz z rodzicem.

Dla lepszego zrozumienia przejdź do dokumentacji Jboss lub możesz użyć hibernate.show_sql=true dla swojej aplikacji i sprawdzić zapytania wystawione przez hibernate.

 0
Author: user1157635,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-12 19:37:24