Java Persistence API 및 Hibernate의 초보자입니다.
차이 무엇 FetchType.LAZY
과 FetchType.EAGER
자바 퍼시스턴스 API 인은?
Java Persistence API 및 Hibernate의 초보자입니다.
차이 무엇 FetchType.LAZY
과 FetchType.EAGER
자바 퍼시스턴스 API 인은?
답변:
때로는 두 개의 엔티티가 있고 그들 사이에 관계가 있습니다. 예를 들어,이라는 엔터티 University
와 라는 다른 엔터티가 Student
있고 대학교에는 많은 학생이있을 수 있습니다.
대학교 단체는 아이디, 이름, 주소 등과 같은 몇 가지 기본 속성과 특정 대학교의 학생 목록을 반환하는 학생이라는 수집 속성을 가질 수 있습니다.
public class University {
private String id;
private String name;
private String address;
private List<Student> students;
// setters and getters
}
이제 데이터베이스에서 University를로드하면 JPA가 해당 ID, 이름 및 주소 필드를로드합니다. 그러나 학생들을 어떻게로드해야하는지에 대한 두 가지 옵션이 있습니다.
getStudents()
방법 을 호출 할 때 필요에 따라 (즉, 게으르게)로드합니다 .대학에 많은 학생이있을 경우, 특히 필요하지 않을 때 모든 학생을 함께 불러오는 것이 비효율적이며, 그러한 경우 학생이 실제로 필요할 때 학생들을 불러 들이기를 원한다고 선언 할 수 있습니다. 이것을 게으른 로딩이라고합니다.
다음 students
은 간절히로드되도록 명시 적으로 표시된 예입니다 .
@Entity
public class University {
@Id
private String id;
private String name;
private String address;
@OneToMany(fetch = FetchType.EAGER)
private List<Student> students;
// etc.
}
다음 students
은 명시 적으로 게으르게로드되도록 표시된 예제 입니다.
@Entity
public class University {
@Id
private String id;
private String name;
private String address;
@OneToMany(fetch = FetchType.LAZY)
private List<Student> students;
// etc.
}
getStudents()
하지만이 방법으로 인해 시간이 걸리지 않는 경우도 있습니다. 이 호출되면 세션이 이미 닫히고 엔티티가 분리됩니다. 마찬가지로, 때때로 클라이언트 / 서버 아키텍처 (예 : Swing 클라이언트 / JEE 서버)가 있고 엔티티 / DTO가 유선으로 클라이언트로 전송되며, 이러한 시나리오에서는 엔티티의 방식으로 인해 지연 로딩이 작동하지 않는 경우가 종종 있습니다 와이어를 통해 직렬화됩니다.
getStudents()
메서드를 처음 호출 하면 결과가 캐시됩니까? 다음에 더 빨리 그 결과에 액세스 할 수 있도록?
EAGER
컬렉션을로드한다는 것은 부모를 가져올 때 완전히 가져 오는 것을 의미합니다. 당신이 가지고 Course
있고 그것을 가지고 있다면 List<Student>
, 모든 학생들은 데이터베이스 를 가져올 때 데이터베이스 에서 Course
가져옵니다.
LAZY
반면 List
에는 액세스하려는 경우에만 의 내용을 가져옵니다. 예를 들어을 호출하여 course.getStudents().iterator()
. 에서 액세스 방법을 List
호출하면 요소를 검색하기 위해 데이터베이스에 대한 호출이 시작됩니다. 이것은 List
(또는 Set
) 주위에 프록시를 생성하여 구현됩니다 . 당신의 게으른 모음 그래서, 구체적인 유형은하지 ArrayList
와 HashSet
있지만, PersistentSet
및 PersistentList
(또는 PersistentBag
)
course.getStudents()
SQL 쿼리를 실행합니다 (콘솔에서 보았습니다). Lazy fetch type에서도 같은 일이 발생합니다. 차이점은 무엇입니까 ??
fetchtype = LAZY
getter hibernete로 컬렉션을 가져 오려고 시도해도 평가할 수 없다는 오류가 발생하더라도 기본 설정으로 설정 한 경우이 질문에 대답 해 주시겠습니까?
성능 및 메모리 사용률을 고려할 수 있습니다. 한 가지 큰 차이점은 EAGER 페치 전략으로 세션없이 페치 된 데이터 오브젝트를 사용할 수 있다는 것입니다. 왜?
세션이 연결될 때 오브젝트에 표시된 데이터를 열망하면 모든 데이터가 페치됩니다. 그러나 지연로드 전략의 경우, 세션이 연결 해제 된 경우 ( session.close()
명령문 이후 ) 지연로드 표시 오브젝트는 데이터를 검색하지 않습니다 . 최대 절전 모드 프록시로 만들 수있는 모든 것. Eager 전략을 사용하면 세션을 닫은 후에도 데이터를 계속 사용할 수 있습니다.
기본적으로 모든 콜렉션 및 맵 오브젝트의 페치 규칙은 FetchType.LAZY
다른 규칙의 경우 FetchType.EAGER
정책을 따릅니다 .
간단히, @OneToMany
그리고 @ManyToMany
관계는 implicictly 관련 객체 (수집 및지도)를 가져 오지 않고 검색 작업을에서 필드를 통해 직렬로 연결된 @OneToOne
과 @ManyToOne
사람.
모두 FetchType.LAZY
와 FetchType.EAGER
정의하는 데 사용하는 기본 계획을 가져 .
불행히도 LAZY 페치에 대한 기본 페치 계획 만 대체 할 수 있습니다. EAGER 가져 오기는 유연성이 떨어지고 많은 성능 문제가 발생할 수 있습니다 .
가져 오기는 쿼리 시간 책임이므로 연결을 EAGER로 만드는 충동을 억제하는 것이 좋습니다. 따라서 모든 쿼리는 fetch 지시문을 사용 하여 현재 비즈니스 사례에 필요한 항목 만 검색해야합니다.
로부터 자바 독 :
EAGER 전략은 데이터를 열심히 가져와야하는 지속성 제공자 런타임의 요구 사항입니다. LAZY 전략은 데이터가 처음 액세스 될 때 느리게 페치되어야한다는 지속성 제공자 런타임에 대한 힌트입니다.
예를 들어, 열심이 게으른 것보다 더 적극적입니다. 게으른 사람은 처음 사용할 때만 (제공자가 힌트를 얻는 경우) 발생하지만 열망하는 일이 있으면 미리 가져올 수 있습니다.
Lazy
가져 오기 유형은 명시 적으로 표시하지 않는 한 Hibernate에 의해 선택된 디폴트로 Eager
유형을 가져옵니다. 보다 정확하고 간결하게하기 위해 다음과 같이 차이점을 설명 할 수 있습니다.
FetchType.LAZY
= getter 메소드를 통해 호출하지 않으면 관계를로드하지 않습니다.
FetchType.EAGER
= 모든 관계를로드합니다.
이 두 가지 인출 유형의 장단점.
Lazy initialization
불필요한 계산을 피하고 메모리 요구량을 줄임으로써 성능을 향상시킵니다.
Eager initialization
더 많은 메모리를 소비하고 처리 속도가 느립니다.
그런 말을하는 데, 상황에 따라 하나이 초기화 중 하나를 사용할 수 있습니다.
getMember
는 멤버의 이름 패턴과 정확히 일치하는 호출 된 함수가 호출 될 때까지 특성로드를 연기 합니까?
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();
}
}
}
Main.java의 retrieve () 메소드를 확인하십시오. Subject를 받으면 으로 주석이 달린 컬렉션 listBooks@OneToMany
가 느리게로드됩니다. 수집의하지만, 다른 한편으로는, 책 관련 협회 주제 로 주석, @ManyToOne
에 의해 eargerly로드 ( [default][1]
대한@ManyToOne
, fetchType=EAGER
). @OneToMany
Subject.java 에 fetchType.EAGER를 배치 하거나 Books.java에 fetchType.LAZY를 배치하여 동작을 변경할 수 있습니다 @ManyToOne
.
public enum FetchType extends java.lang.Enum 데이터베이스에서 데이터를 가져 오기위한 전략을 정의합니다. EAGER 전략은 데이터를 열심히 가져와야하는 지속성 제공자 런타임의 요구 사항입니다. LAZY 전략은 데이터가 처음 액세스 될 때 느리게 페치되어야한다는 지속성 제공자 런타임에 대한 힌트입니다. 구현시 LAZY 전략 힌트가 지정된 데이터를 열심히 가져올 수 있습니다. 예 : @Basic (fetch = LAZY) 보호 문자열 getName () {return name; }
위의 "경환 민"의 말에이 메모를 추가하고 싶습니다.
이 간단한 설계자와 함께 Spring Rest를 사용한다고 가정하십시오.
컨트롤러 <-> 서비스 <-> 리포지토리
을 사용하는 경우 일부 데이터를 프런트 엔드로 FetchType.LAZY
반환하려고합니다. 서비스에서 세션이 닫혀 있으므로 컨트롤러 메소드로 데이터를 반환하면 예외가 발생합니다.JSON Mapper Object
데이터를 가져올 수 없으므로 합니다.
디자인, 성능 및 개발자에 따라이 문제를 해결하기위한 세 가지 공통 옵션이 있습니다.
FetchType.EAGER
하는 것이므로 세션이 컨트롤러 메소드에서 계속 활성화됩니다.FetchType.LAZY
변환기 방법과 함께 사용 하여 데이터 Entity
를 다른 데이터 개체 DTO
로 전송하고 컨트롤러로 전송하는 것입니다. 따라서 세션이 닫히더라도 예외는 없습니다.@ drop-shadow Hibernate를 사용 Hibernate.initialize()
하는 경우 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;
}
//...
}
LAZY : 자식 엔터티를 느리게 가져옵니다. 즉, 부모 엔터티를 가져올 때 자식 엔터티의 프록시 (cglib 또는 다른 유틸리티에서 생성)를 가져 오며 자식 엔터티의 속성에 액세스하면 실제로 최대 절전 모드로 가져옵니다.
EAGER : 상위 엔티티와 함께 하위 엔티티를 가져옵니다.
이해를 돕기 위해 Jboss 문서로 이동하거나 hibernate.show_sql=true
앱에 사용 하고 최대 절전 모드에서 발행 한 쿼리를 확인할 수 있습니다 .