it-swarm.com.de

Unterschied zwischen FetchType LAZY und EAGER in Java Persistence API?

Ich bin ein Neuling in Java Persistence API und Hibernate.

Was ist der Unterschied zwischen FetchType.LAZY und FetchType.EAGER in Java Persistence API?

487
leon

Manchmal haben Sie zwei Entitäten und es gibt eine Beziehung zwischen ihnen. Beispielsweise könnten Sie eine Entität mit dem Namen University und eine andere Entität mit dem Namen Student haben.

Die Universitätsentität verfügt möglicherweise über einige grundlegende Eigenschaften wie ID, Name, Adresse usw. sowie über eine Eigenschaft namens "Studenten":

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

 // setters and getters
}

Wenn Sie nun eine Universität aus der Datenbank laden, lädt JPA die Felder für ID, Name und Adresse für Sie. Sie haben jedoch zwei Möglichkeiten für Studenten: Sie können es zusammen mit den übrigen Feldern laden (d. H. Eifrig) oder Sie können es bei Bedarf laden (d. H. Faul), wenn Sie die getStudents () -Methode der Universität aufrufen.

Wenn eine Universität viele Studenten hat, ist es nicht effizient, alle Studenten damit zu laden, wenn sie nicht gebraucht werden. In solchen Fällen können Sie also angeben, dass die Schüler geladen werden sollen, wenn sie tatsächlich benötigt werden. Dies wird als verzögertes Laden bezeichnet.

938
Behrang

Grundsätzlich gilt,

LAZY = fetch when needed
EAGER = fetch immediately
255
unbeli

EAGER Das Laden von Sammlungen bedeutet, dass sie zum Zeitpunkt des Abrufs ihres übergeordneten Elements vollständig abgerufen werden. Wenn Sie also Course haben und es List<Student> hat, werden alle Schüler abgerufen aus der Datenbank zu dem Zeitpunkt, an dem Course abgerufen wird.

LAZY bedeutet andererseits, dass der Inhalt von List nur abgerufen wird, wenn Sie versuchen, darauf zuzugreifen. Zum Beispiel durch Aufrufen von course.getStudents().iterator(). Durch Aufrufen einer Zugriffsmethode für List wird ein Aufruf an die Datenbank initiiert, um die Elemente abzurufen. Dies wird implementiert, indem ein Proxy um das List (oder Set) erstellt wird. Für Ihre faulen Sammlungen sind die konkreten Typen also nicht ArrayList und HashSet, sondern PersistentSet und PersistentList (oder PersistentBag).

63
Bozho

Ich kann Leistung und Speichernutzung berücksichtigen. Ein großer Unterschied besteht darin, dass mit der EAGER-Abrufstrategie abgerufene Datenobjekte ohne Sitzung verwendet werden können. Warum?
Alle Daten werden abgerufen, wenn eifrig markierte Daten im Objekt vorhanden sind, wenn die Sitzung verbunden ist. Bei einer Strategie für verzögertes Laden ruft das markierte Objekt für verzögertes Laden keine Daten ab, wenn die Sitzung getrennt wird (nach der Anweisung session.close()). All dies kann über den Ruhezustand-Proxy erfolgen. Eager Strategy sorgt dafür, dass die Daten auch nach dem Schließen der Sitzung noch verfügbar sind.

14
Kyung Hwan Min

Standardmäßig lautet die Abrufregel für alle Erfassungs- und Kartenobjekte FetchType.LAZY und für andere Instanzen folgt sie der Richtlinie FetchType.EAGER.
Kurz gesagt, mit den Beziehungen @OneToMany und @ManyToMany werden die zugehörigen Objekte (Sammlung und Karte) nicht implizit abgerufen, sondern der Abrufvorgang wird über das Feld in @OneToOne und @ManyToOne Einsen.

(mit freundlicher Genehmigung von - objectdbcom)

11
babai

Nach meinem Wissen hängt die Art des Abrufs von Ihrer Anforderung ab.

FetchType.LAZY ist auf Anfrage (d. H. Wenn wir die Daten benötigt haben).

FetchType.EAGER ist unmittelbar (d. H. Bevor unsere Anforderung eintritt, holen wir den Datensatz unnötigerweise ab)

10
JDGuide

Sowohl FetchType.LAZY als auch FetchType.EAGER werden verwendet, um den Standardabrufplan zu definieren.

Leider können Sie nur den Standardabrufplan für das LAZY-Abrufen überschreiben. EAGER-Abruf ist weniger flexibel und kann führt zu vielen Leistungsproblemen .

Mein Rat ist, den Drang zu unterdrücken, Ihre Assoziationen zu EAGER zu machen, da das Abrufen in der Verantwortung der Abfragezeit liegt. Daher sollten alle Ihre Abfragen die Anweisung fetch verwenden, um nur das abzurufen, was für den aktuellen Geschäftsfall erforderlich ist.

9
Vlad Mihalcea

Aus dem Javadoc :

Die EAGER-Strategie ist eine Anforderung an die Laufzeit des Persistenzanbieters, dass Daten unbedingt abgerufen werden müssen. Die LAZY-Strategie ist ein Hinweis für die Laufzeit des Persistenzanbieters, dass Daten beim ersten Zugriff verzögert abgerufen werden sollten.

Zum Beispiel ist eifrig proaktiver als faul. Lazy tritt nur bei der ersten Verwendung auf (wenn der Anbieter den Hinweis annimmt), wohingegen bei eifrigen Dingen (möglicherweise) vorabgerufen wird.

6
T.J. Crowder

Der Abruftyp Lazy ist standardmäßig im Ruhezustand ausgewählt, es sei denn, Sie markieren den Abruftyp Eager ausdrücklich. Um genauer und prägnanter zu sein, kann der Unterschied wie folgt angegeben werden.

FetchType.LAZY = Dies lädt die Beziehungen nur, wenn Sie sie über die Getter-Methode aufrufen.

FetchType.EAGER = Lädt alle Beziehungen.

Vor- und Nachteile dieser beiden Abruftypen.

Lazy initialization verbessert die Leistung, indem unnötige Berechnungen vermieden und der Speicherbedarf verringert werden.

Eager initialization beansprucht mehr Speicher und die Verarbeitungsgeschwindigkeit ist langsam.

Abgesehen davon kann abhängig von der Situation eine dieser Initialisierungen verwendet werden.

4
Dulith De Costa

Book.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;
        }

        }

Subject.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();
        }
    }

    }

Überprüfen Sie die retrieve () -Methode von Main.Java. Wenn wir Subject erhalten, wird die mit @OneToMany kommentierte Sammlung listBooks träge geladen. Auf der anderen Seite wird die mit @ManyToOne beschriftete Bücherassoziation des Sammelfachs (von [default][1] für @ManyToOne, fetchType=EAGER). Sie können das Verhalten ändern, indem Sie fetchType.EAGER in @OneToMany Subject.Java oder fetchType.LAZY in @ManyToOne in Books.Java platzieren.

3
Deepak

public enum FetchType erweitert Java.lang.Enum Definiert Strategien zum Abrufen von Daten aus der Datenbank. Die EAGER-Strategie ist eine Anforderung an die Laufzeit des Persistenzanbieters, dass Daten unbedingt abgerufen werden müssen. Die LAZY-Strategie ist ein Hinweis für die Laufzeit des Persistenzanbieters, dass Daten beim ersten Zugriff verzögert abgerufen werden sollten. Die Implementierung darf eifrig Daten abrufen, für die der LAZY-Strategie-Hinweis angegeben wurde. Beispiel: @Basic (fetch = LAZY) protected String getName () {return name; }

Quelle

1
Anas Lachheb

Ich möchte diese Notiz zu dem hinzufügen, was "Kyung Hwan Min" oben gesagt hat.

Angenommen, Sie verwenden Spring Rest mit diesem einfachen Architekten:

Controller <-> Service <-> Repository

Und Sie möchten einige Daten an das Front-End zurückgeben. Wenn Sie FetchType.LAZY verwenden, erhalten Sie eine Ausnahme, nachdem Sie Daten an die Controller-Methode zurückgegeben haben, da die Sitzung im Service geschlossen wurde, sodass JSON Mapper Object kann die Daten nicht abrufen.

Es gibt drei gebräuchliche Optionen, um dieses Problem zu lösen, abhängig von Design, Leistung und Entwickler:

  1. Am einfachsten ist es, FetchType.EAGER zu verwenden, damit die Sitzung auf der Controller-Methode noch aktiv ist.
  2. Anti-Patterns Lösungen, um die Sitzung bis zum Ende der Ausführung live zu machen, ist dies ein großes Leistungsproblem im System.
  3. Die beste Vorgehensweise ist, FetchType.LAZY mit der Konvertierungsmethode zu verwenden, um Daten von Entity zu einem anderen Datenobjekt DTO zu übertragen und an den Controller zu senden, sodass es keine Ausnahme gibt, wenn die Sitzung geschlossen wird.
0

@ drop-shadow Wenn Sie den Ruhezustand verwenden, können Sie Hibernate.initialize() aufrufen, wenn Sie die getStudents() -Methode aufrufen:

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
Jules Martel

LAZY: Ruft die untergeordneten Entitäten träge ab, d. H., Wenn die übergeordnete Entität abgerufen wird, ruft sie nur den Proxy (erstellt von cglib oder einem anderen Dienstprogramm) der untergeordneten Entitäten ab, und wenn Sie auf eine Eigenschaft der untergeordneten Entität zugreifen, wird sie tatsächlich im Ruhezustand abgerufen.

EAGER: Ruft die untergeordneten Entitäten zusammen mit den übergeordneten Entitäten ab.

Zum besseren Verständnis rufen Sie die Jboss-Dokumentation auf, oder Sie können hibernate.show_sql=true für Ihre App verwenden und die vom Ruhezustand ausgegebenen Abfragen überprüfen.

0
user1157635