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?
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:
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:
- aby załadować go razem z resztą pól (np.]}
- , 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.
}
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
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
)
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.
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)
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
.
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.
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.
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.
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.
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ć.
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.
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:
- najłatwiej jest użyć
FetchType.EAGER
, aby sesja nadal żyła przy metodzie kontrolera, ale ta metoda wpłynie na wydajność. - anty-patterns rozwiązania, aby sesja trwała do końca wykonania, jest to ogromny problem wydajności w systemie.
- najlepszą praktyką jest użycie
FetchType.LAZY
z maperem podobnym doMapStruct
do przeniesienia danych zEntity
do innego obiektu danychDTO
, a następnie odesłanie go z powrotem do kontrolera, więc nie ma wyjątku, jeśli sesja zostanie zamknięta.
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;}
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;
}
//...
}
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.
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