programing

Java Persistence API에서 FetchType LAGY와 OVER의 차이점은 무엇입니까?

bestcode 2022. 8. 28. 09:40
반응형

Java Persistence API에서 FetchType LAGY와 OVER의 차이점은 무엇입니까?

저는 Java Persistence API와 Hibernate를 처음 접하는 사람입니다.

Java Persistence API 와의 차이점은 무엇입니까?

때때로 당신은 두 개의 실체를 가지고 있고 그들 사이에는 관계가 있다.를 들어, '하다'라는 수 .University 라고 하는 실체Student을 사용법

University 엔티티는 ID, 이름, 주소 등의 몇 가지 기본 속성뿐만 아니라 특정 대학의 학생 목록을 반환하는 students라는 컬렉션 속성을 가질 수 있습니다.

대학에는 많은 학생들이 있다.

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

   // setters and getters
}

데이터베이스에서 University를 로드하면 JPA가 ID, 이름 및 주소 필드를 로드합니다.그러나 학생을 로드하는 방법에는 다음 두 가지 옵션이 있습니다.

  1. 다른 필드와 함께 로드하기(열심히 로드) 또는
  2. 방법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.
}

기본적으로는

LAZY = fetch when needed
EAGER = fetch immediately

EAGER컬렉션을 로드하는 것은 부모 컬렉션을 가져올 때 컬렉션을 완전히 가져오는 것을 의미합니다. 만약에 ★★★★★★★★★★★★★★★★★★★★★★★.Course그리고 그것은 가지고 있다List<Student>, 모든 학생이 데이터베이스로부터 취득됩니다.Course져옵니니다다

LAZY에 '하다, 하다, 하다', '', '하다', '다,List액세스하려고 할 때만 취득됩니다.를 들어, 「」를 호출하면, 「」가 됩니다.course.getStudents().iterator()를 호출합니다.List는 요소를 취득하기 위한 데이터베이스 호출을 시작합니다.은, 「프록시」의 에 「를.List (오류)Set 게으른 컬렉션의 은 (가 아닙니다ArrayList ★★★★★★★★★★★★★★★★★」HashSetPersistentSet ★★★★★★★★★★★★★★★★★」PersistentList (오류)PersistentBag)

퍼포먼스와 메모리 사용률을 고려할 수 있습니다. 중 하나는 Eager 된 데이터 할 수 요? 유는는무?무 엇??
세션이 연결되어 있을 때 개체에서 빠르게 표시된 데이터가 있으면 모든 데이터가 가져옵니다.전략의 는 세션이 끊어지면).session.close()이치노이 모든 것은 최대 절전 프록시로 만들 수 있습니다.열성적인 전략으로 세션을 종료한 후에도 데이터를 계속 사용할 수 있습니다.

모든 및은 """입니다.FetchType.LAZY, 그 에서는, 「」의 에 이어집니다.FetchType.EAGER★★★★★★ 。
로 말하면, 「 」입니다.@OneToMany ★★★★★★★★★★★★★★★★★」@ManyToMany 오브젝트및 맵)를 있게 은 relations의 .@OneToOne ★★★★★★★★★★★★★★★★★」@ManyToOnediscloss.discloss.

(예:- objectdbcom)

제가 아는 바로는 두 가지 유형의 가져오기 모두 귀하의 요구 사항에 따라 다릅니다.

FetchType.LAZY온 디맨드(데이터가 필요한 시점)입니다.

FetchType.EAGER는 즉시입니다하기 전에 불필요하게 ).

두 가지 유형의 가져오기 간의 주요 차이점은 데이터가 메모리에 로드되는 순간입니다.
이해를 돕기 위해 사진 2장을 첨부했습니다.

fetch ★★★★★★★★★★★★★★」
열심 가져오기

느릿느릿 가져오기

다.FetchType.LAZY ★★★★★★★★★★★★★★★★★」FetchType.EAGER기본 가져오기 계획을 정의하는 데 사용됩니다.

안타깝게도 LAGY 가져오기 기본 가져오기 계획만 재정의할 수 있습니다.EIGER 가져오기 기능은 유연성이 떨어지며 많은 성능 문제가 발생할 수 있습니다.

페치는 쿼리 타임의 책임이기 때문에, 당신의 어소시에이션을 열렬히 만들고 싶은 충동을 억제하는 것이 제 조언입니다.따라서 모든 쿼리는 fetch 디렉티브를 사용하여 현재 비즈니스 케이스에 필요한 것만 검색해야 합니다.

Lazy단, 「Fetch type」은 「Fibernate」로 으로 마크 되어 있지 않습니다.Eager가져오기 유형.보다 정확하고 간결하게 하기 위해 다음과 같이 차이를 말할 수 있습니다.

FetchType.LAZY= getter 메서드를 통해 호출하지 않으면 관계가 로드되지 않습니다.

FetchType.EAGER=아니다

이 두 가지 가져오기 유형의 장단점.

Lazy initialization불필요한 계산을 피하고 메모리 요건을 줄임으로써 성능을 향상시킵니다.

Eager initialization메모리 소비량이 증가하여 처리 속도가 느립니다.

, 상황에 따라서는 이러한 초기화 중 하나를 사용할 수 있습니다.

위의 내용에 이 메모를 추가하고 싶습니다.

스프링(MVC 및 데이터)을 다음과 같은 단순한 설계자와 함께 사용한다고 가정합니다.

컨트롤러 <-> 서비스 <-> 저장소

FetchType.LAZY하면 ' , 으면 안 돼요.LazyInitializationException이 후.JSON Mapper Object데이터를 가져올 수 없습니다.

설계, 성능 및 개발자에 따라 이 문제를 해결하기 위한 두 가지 일반적인 옵션이 있습니다.

  1. 가장 쉬운 것은 사용하는 것입니다.FetchType.EAGER세션은 컨트롤러 방식으로 활성화되지만 이러한 방식은 성능에 영향을 미칩니다.
  2. 를 사용하는 .FetchType.LAZY) MapStructEntity 오브젝트에 DTO그 후 컨트롤러로 반송하기 때문에 세션이 종료되어도 예외는 없습니다.

간단한 예를 다음에 제시하겠습니다.

@RestController
@RequestMapping("/api")
public class UserResource {

    @GetMapping("/users")
    public Page<UserDTO> getAllUsers(Pageable pageable) {
        return userService.getAllUsers(pageable);
    }
}

@Service
@Transactional
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Transactional(readOnly = true)
    public Page<UserDTO> getAllUsers(Pageable pageable) {
        return userRepository.findAll(pageable).map(UserDTO::new);
    }
}

@Repository
public interface UserRepository extends JpaRepository<User, String> {

    Page<User> findAll(Pageable pageable);
}

public class UserDTO {

    private Long id;

    private String firstName;

    private String lastName;

    private String email;
    
    private Set<String> addresses;

    public UserDTO() {
        // Empty constructor needed for Jackson.
    }

    public UserDTO(User user) {
        this.id = user.getId();
        this.firstName = user.getFirstName();
        this.lastName = user.getLastName();
        this.email = user.getEmail();
        this.addresses = user.getAddresses().stream()
            .map(Address::getAddress)
            .collect(Collectors.toSet());
    }

    // Getters, setters, equals, and hashCode
}

@Entity
@Table(name = "user")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String firstName;

    @Column
    private String lastName;

    @Column(unique = true)
    private String email;
    
    @OneToMany(mappedBy = "address", fetch = FetchType.LAZY)
    private Set<Address> addresses = new HashSet<>();

    // Getters, setters, equals, and hashCode
}

@Entity
@Table(name = "address")
public class Address implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String address;

    @ManyToOne
    @JsonIgnoreProperties(value = "addesses", allowSetters = true)
    private User user;

    // Getters, setters, equals, and hashCode
}

Javadoc에서:

AGER 전략은 지속성 공급자 런타임에 데이터를 빠르게 가져와야 하는 요구 사항입니다.LAGY 전략은 데이터를 처음 액세스할 때 데이터를 느리게 가져와야 한다는 지속성 공급자 런타임에 대한 힌트입니다.

예를 들어, 열정은 게으름보다 능동적입니다.게으름은 처음 사용했을 때(공급자가 힌트를 얻은 경우)에만 발생하지만, 열심인 경우에는 미리 가져올 수 있습니다.

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

    }

휴지 상태 Util.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이 거칠다.[default][1]★★★★★★에@ManyToOne,fetchType=EAGERfetchType fetch fetch fetch fetch 。@OneToManySubject.java fetchType 입니다. ★★★★@ManyToOneBooks.java.

public Enum FetchType은 java.lang을 확장합니다.Enum 데이터베이스에서 데이터를 가져오는 전략을 정의합니다.AGER 전략은 지속성 공급자 런타임에 데이터를 빠르게 가져와야 하는 요구 사항입니다.LAGY 전략은 데이터를 처음 액세스할 때 데이터를 느리게 가져와야 한다는 지속성 공급자 런타임에 대한 힌트입니다.구현에서는 LAGY 전략 힌트가 지정된 데이터를 빠르게 가져올 수 있습니다.예: @Basic(fetch=)LAGY) 보호 문자열 getName() {return name;}

원천

JOIN

쉽게 받아들이세요.

이라고 User그리고 또 다른 수업인Address또, 다음의 조작을 실행했을 경우, 유저에게, 1 대 다의 관계를 나타내는 주소가 1 개 이상 있다고 가정합니다.

FetchType.LAZY sql 명령어 실행(예:join:

SELECT * FROM users 

FetchType.EAGER 안에서와 같이 sql 명령 실행join:

SELECT * FROM users u join address a on a.user_id = u.user_id

주의: 위의 쿼리는 이미지를 명확하게 하기 위해서만 유효하지만 실제로는 Hibernate 프레임워크가 위의 유사한 쿼리를 실행합니다.

어떤 Fetch Type이 더 좋습니까?

  • 빠른 가져오기 기능은 모든 관계를 자동으로 로드하기 때문에 성능이 매우 우수합니다.
  • 게으른 페치는 지시하지 않는 한 어떠한 관계도 로드하지 않으므로 성능이 향상됩니다.
  • 필요한 코드가 적기 때문에 빠르게 가져오기 때문에 프로그래밍이 용이함
  • 로딩이 느리면 시스템 전체가 올바르게 테스트되지 않으면 버그(예외)가 발생할 수 있습니다.
  • 모든 것을 고려해 볼 때, 여전히 레이지 로딩이 더 성능적이기 때문에 레이지 로딩을 선호해야 합니다.

Spring Boot Framework를 사용하는 경우 파일을 작성하여 다음 명령을 추가하여 정확히 무슨 일이 일어나고 있는지 확인합니다.

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

이러한 차이를 이해하는 가장 좋은 방법은 게으름을 이해하는 것입니다.Fetch Type(페치 타입)LAGY는 관계를 사용할 때 데이터베이스에서 관련 엔티티만 가져오도록 휴지 상태를 지시합니다.

추신: 지금까지 작업한 많은 프로젝트에서 소프트웨어 개발자들이 관심을 기울이지 않고 있으며, 심지어 자신을 선배라고 부르는 사람들도 있습니다.작업 중인 프로젝트가 대량의 데이터로 데이터를 교환하지 않는 경우 여기에서 EIGER를 사용하는 것이 좋습니다.단, n+1 문제가 발생할 수 있는 문제를 고려하여 기본적으로 관계의 가져오기 유형을 파악한 후 이러한 문제에 유의해야 합니다.

여기서 기본값을 확인할 수 있습니다.휴지 상태에서의 일대일, 다대일 및 일대다 기본 가져오기 유형

또, 페치 타입을 이해하고 나서도, 거기서 끝나지 않습니다.LAGY를 사용하는 시기와 AGER를 사용하는 시기를 이해하려면 단방향과 양방향의 개념도 이해해야 합니다.또한 스프링 부트 저장소에는 데이터를 읽을 수 있는 몇 가지 방법이 있습니다.를 들면, 「」는,getOne() ★★★★★★★★★★★★★★★★★」getById()메서드를 사용하면 엔티티에서 데이터를 느리게 가져올 수 있습니다.요컨대, 당신이 무엇을 언제 사용하느냐는 상대방이 당신에게 무엇을 해주기를 바라는가에 달려있다.

@ 상태를하는 경우 @drop-shadow로 호출할 수 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;
    }
    //...
}

LAGY: 하위 엔티티를 느리게 가져옵니다. 즉, 상위 엔티티를 가져올 때 하위 엔티티의 프록시(cglib 또는 기타 유틸리티에 의해 작성됨)만 가져오고 하위 엔티티의 속성에 액세스하면 실제로 휴지 상태로 가져옵니다.

INGER: 상위 엔티티와 함께 하위 엔티티를 가져옵니다.

내용은 하거나 Jboss 문서를 하십시오.hibernate.show_sql=truesubernate에 합니다.

언급URL : https://stackoverflow.com/questions/2990799/difference-between-fetchtype-lazy-and-eager-in-java-persistence-api

반응형