Unterschied zwischen fetchtype faul und eifrig in der Java -Persistenz -API?
-
24-10-2019 - |
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?
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:
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:
- Um es zusammen mit den restlichen Feldern (dh eifrig) zu laden oder
- 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.
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; }
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:
- Das einfachste ist zu verwenden
FetchType.EAGER
, So dass die Sitzung bei der Controller -Methode noch lebt. - Anti-Muster Lösungen, um die Sitzung live zu gestalten, bis die Ausführung endet, macht es ein großes Leistungsproblem im System.
- Die beste Praxis ist zu verwenden
FetchType.LAZY
mit Konvertermethode, um Daten von zu übertragenEntity
zu einem anderen DatenobjektDTO
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.