Frage

Ich bin ein Neuling von Java Persistence API und Winterschlaf.

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

War es hilfreich?

Lösung

Manchmal haben Sie zwei Einheiten und es gibt eine Beziehung zwischen ihnen. Zum Beispiel haben Sie möglicherweise eine Entität aufgerufen University und eine andere Entität namens Student Und eine Universität könnte viele Studenten haben:

Die Universitätseinheit hat möglicherweise einige grundlegende Immobilien wie ID, Name, Adresse usw. sowie eine Sammeleigenschaft namens Studenten, die die Liste der Studenten für eine bestimmte Universität zurückgibt:

A university has many students

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 ihre ID-, Name- und Adressfelder für Sie. Sie haben jedoch zwei Möglichkeiten, wie die Schüler geladen werden sollten:

  1. Um es zusammen mit den restlichen Feldern (dh eifrig) zu laden oder
  2. So laden Sie es auf Nachfrage (dh faul), wenn Sie die Universität anrufen getStudents() Methode.

Wenn eine Universität viele Studenten hat, ist es nicht effizient, alle Studenten zusammen zu laden, insbesondere wenn sie nicht benötigt wird, und in solchen Fällen können Sie erklären, dass Sie möchten, dass die Schüler geladen werden, wenn sie tatsächlich benötigt werden. Dies wird als fauler Laden bezeichnet.

Hier ist ein Beispiel, wo students wird explizit als eifrig markiert:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

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

    // etc.    
}

Und hier ist ein Beispiel wo students wird explizit als träge geladen:

@Entity
public class University {

    @Id
    private String id;

    private String name;

    private String address;

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

    // etc.
}

Andere Tipps

Grundsätzlich,

LAZY = fetch when needed
EAGER = fetch immediately

EAGER Das Laden von Sammlungen bedeutet, dass sie zum Zeitpunkt der abgerufenen Eltern vollständig abgerufen werden. Also wenn du hast Course und es hat List<Student>, alle Schüler sind abgerufen aus der Datenbank zu der Zeit der Zeit Course ist abgerufen.

LAZY Andererseits bedeutet der Inhalt des List werden nur abgerufen, wenn Sie versuchen, darauf zuzugreifen. Zum Beispiel durch Anruf course.getStudents().iterator(). Aufrufen einer beliebigen Zugriffsmethode auf der List Initiieren Sie einen Anruf in die Datenbank, um die Elemente abzurufen. Dies wird implementiert, indem ein Proxy rund um das erstellt wird List (oder Set). Für Ihre faulen Sammlungen sind die Betontypen also nicht ArrayList und HashSet, aber PersistentSet und PersistentList (oder PersistentBag)

Ich kann die Leistung und Speicherauslastung in Betracht ziehen. Ein großer Unterschied besteht darin, dass die eifrige Abrufstrategie ein abgerufenes Datenobjekt ohne Sitzung verwenden kann. Wieso den?
Alle Daten werden abgerufen, wenn eifrige markierte Daten im Objekt bei Verbindung der Sitzung. Im Falle einer faulen Ladestrategie ruft das faule Laden markierte Objekt jedoch keine Daten ab, wenn die Sitzung getrennt ist (danach session.close() Aussage). Alles, was durch Hibernate -Proxy gemacht werden kann. Mit eifriger Strategie können Daten nach Abschluss der Sitzung noch verfügbar sein.

Standardmäßig ist für alle Sammlungs- und Kartenobjekte die Abrufregel lautet FetchType.LAZY und für andere Fälle folgt es dem FetchType.EAGER Politik.
In Kürze, @OneToMany und @ManyToMany Die Beziehungen holt nicht die zugehörigen Objekte (Sammlung und Karte) implizit ab, aber der Abrufoperation wird durch das Feld in kaskadiert @OneToOne und @ManyToOne Einsen.

(Mit freundlicher Genehmigung:- ObjectDBCom)

Nach meinem Wissen hängt beide Arten des Abrufs von Ihrer Anforderung ab.

FetchType.LAZY ist auf Bedarf (dh wenn wir die Daten benötigten).

FetchType.EAGER ist unmittelbar (dh bevor unsere Anforderung kommt, holen wir unnötig die Aufzeichnung)

Beide FetchType.LAZY und FetchType.EAGER werden verwendet, um die zu definieren Standard -Fetch -Plan.

Leider können Sie nur den Standard -Fetch -Plan für das faule Fetching überschreiben. Das eifrige Abrufen ist weniger flexibel und kann führen zu vielen Leistungsproblemen.

Mein Rat ist, den Drang einzuschränken, Ihre Verbände eifrig zu gestalten, da das Abholen eine Anfragungsverantwortung darstellt. Alle Ihre Fragen sollten also die verwenden bringen Richtlinie, um nur das abzurufen, was für den aktuellen Business Case erforderlich ist.

Von dem Javadoc:

Die eifrige Strategie ist eine Voraussetzung für die Laufzeit des Persistenzanbieters, dass Daten eifrig abgerufen werden müssen. Die faule Strategie ist ein Hinweis auf die Laufzeit des Persistenzanbieters, dass Daten träge abgerufen werden sollten, wenn sie zum ersten Mal zugegriffen werden.

ZB eifrig ist proaktiver als faul. Lazy passiert nur beim ersten Gebrauch (wenn der Anbieter den Hinweis nimmt), während mit eifrigen Dingen (Mai) vorgeholt wird.

Das Lazy Der Abruftyp wird standardmäßig von Hibernate ausgewählt, es sei denn, Sie markieren explizit Eager Typ abrufen. Um genauer und prägnanter zu sein, kann der Unterschied wie unten angegeben werden.

FetchType.LAZY = Dies lädt die Beziehungen nicht, es sei denn, Sie rufen sie über die Getter -Methode auf.

FetchType.EAGER = Dies lädt alle Beziehungen.

Vor- und Nachteile dieser beiden Abruftypen.

Lazy initialization Verbessert die Leistung, indem sie unnötige Berechnungen vermeiden und die Speicheranforderungen reduzieren.

Eager initialization Nimmt mehr Speicherverbrauch und die Verarbeitungsgeschwindigkeit ist langsam.

Allerdings, das, es kommt auf die Situation an Beide dieser Initialisierung kann verwendet werden.

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

        }

Betreff.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 Methode retrieve () von main.java. Wenn wir das Thema bekommen, dann seine Sammlung Listenbücher, kommentiert mit @OneToMany, wird träge geladen. Andererseits bücherbezogene Association of Collection Thema, kommentiert mit @ManyToOne, lädt ohrfrost (von [default][1] zum @ManyToOne, fetchType=EAGER). Wir können das Verhalten ändern, indem wir FetchType.eagern einsetzen @OneToMany Betreff.java oder fetchtype.lazy on @ManyToOne in books.java.

Public Enum FetchType erweitert Java.lang.Enum definiert Strategien zum Abholen von Daten aus der Datenbank. Die eifrige Strategie ist eine Voraussetzung für die Laufzeit des Persistenzanbieters, dass Daten eifrig abgerufen werden müssen. Die faule Strategie ist ein Hinweis auf die Laufzeit des Persistenzanbieters, dass Daten träge abgerufen werden sollten, wenn sie zum ersten Mal zugegriffen werden. Die Implementierung darf eifrig Daten abrufen, für die der faule Strategie -Hinweis angegeben wurde. Beispiel: @Basic (fetch = Lazy) Protected String getName () {return name; }

Quelle

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

Angenommen, Sie verwenden Frühlingsruhe mit diesem einfachen Architekten:

Controller <--> Service <-> Repository

Und Sie möchten einige Daten an das Front-End zurückgeben, wenn Sie verwenden FetchType.LAZY, Sie erhalten eine Ausnahme, nachdem Sie Daten an die Controller -Methode zurückgegeben haben, da die Sitzung im Dienst geschlossen ist, damit die JSON Mapper Object Die Daten können nicht erhalten.

Es gibt drei gängige Optionen, um dieses Problem zu lösen, und hängt von Design, Leistung und dem Entwickler ab:

  1. Das einfachste ist zu verwenden FetchType.EAGER, So dass die Sitzung bei der Controller -Methode noch lebt.
  2. Anti-Muster Lösungen, um die Sitzung live zu gestalten, bis die Ausführung endet, macht es ein großes Leistungsproblem im System.
  3. Die beste Praxis ist zu verwenden FetchType.LAZY mit Konvertermethode, um Daten von zu übertragen Entity zu einem anderen Datenobjekt DTO und senden Sie es an Controller, so dass es keine Ausnahme gibt, wenn die Sitzung geschlossen wurde.

@Drop-Shadow Wenn Sie Hibernate verwenden, können Sie anrufen Hibernate.initialize() Wenn Sie die aufrufen getStudents() Methode:

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

LAZIER: Es holt die Kinderentitäten faul, dh zum Zeitpunkt des Abholens der Elterneinheit holt es nur den Proxy (erstellt von CGlib oder einer anderen Nützlichkeit) der Kindergesellschaft und wenn Sie auf eine Eigenschaft von Kinderunternehmen zugreifen, wird es tatsächlich von Hibernate abgerufen.

Eifrig: Es holt die Kinderentitäten zusammen mit Eltern.

Für ein besseres Verständnis finden Sie die JBoss -Dokumentation oder Sie können verwenden hibernate.show_sql=true für Ihre App und überprüfen Sie die vom Winterschlafausgabe ausgegebenen Fragen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top