LazyCollectionOption.EXTRA 알아보기

그러나 가장 흥미로운 것은 LazyCollectionOption.EXTRA 값입니다. @LazyCollection 주석 의 값으로 지정하면 Hibernate는 컬렉션의 요소 로딩을 가능한 한 오랫동안 지연합니다.

컬렉션의 요소 수를 가져오려는 경우:

User user = session.load(User.class, 1);
List<Comment> comments = user.getComments();
int count = commetns.size();

그런 다음 이 모든 코드에 대해 Hibernate는 단 하나의 쿼리만 실행할 것입니다.

SELECT COUNT(id) FROM comment WHERE user_id = 1;

그러나 컬렉션에서 하나의 주석(예: 3번)을 가져오려는 경우:

User user = session.load(User.class, 1);
List<Comment> comments = user.getComments();
Comment comment = commetns.get(3);

그런 다음 질문이 발생합니다. Hibernate는 모든 요소를 ​​메모리에 로드하지 않고 요소가 세 번째라는 것을 어떻게 알 수 있습니까?

이 문제를 해결하기 위해 주석 테이블에 주석의 서수를 주석 모음에 저장할 추가 열을 만드는 것이 제안됩니다. 또한 이를 위해서는 @OrderColumn 이라는 특별한 주석이 필요합니다 .

그 솔루션은 다음과 같습니다.

@Entity
@Table(name=”user”)
class User {
   @Column(name=”id”)
   public Integer id;

   @OneToMany(cascade = CascadeType.ALL)
   @LazyCollection(LazyCollectionOption.EXTRA)
   @OrderColumn(name = "order_id")
   public List<Comment> comments;
}

LazyCollectionOption.EXTRA의 주요 장점

@ManyToMany 주석 으로 지정할 때 LazyCollectionOption.EXTRA의 가장 큰 이점을 볼 수 있습니다 . Employee와 Task가 있고 한 사용자에게 많은 작업을 할당할 수 있는 이전 사례를 살펴보겠습니다.

Java 클래스는 다음과 같습니다.

직원 클래스 :

@Entity
@Table(name=”employee”)
class Employee {
   @Column(name=”id”)
   public Integer id;

   @ManyToMany(cascade = CascadeType.ALL)
   @JoinTable(name="employee_task",
       	joinColumns=  @JoinColumn(name="employee_id", referencedColumnName="id"),
       	inverseJoinColumns= @JoinColumn(name="task_id", referencedColumnName="id") )
   @LazyCollection(LazyCollectionOption.EXTRA)
   private Set<EmployeeTask> tasks = new HashSet<EmployeeTask>();

}

그리고 EmployeeTask 클래스 :

@Entity
@Table(name=”task”)
class EmployeeTask {
   @Column(name=”id”)
   public Integer id;

   @ManyToMany(cascade = CascadeType.ALL)
   @JoinTable(name="employee_task",
       	joinColumns=  @JoinColumn(name="task_id", referencedColumnName="id"),
       	inverseJoinColumns= @JoinColumn(name=" employee_id", referencedColumnName="id") )
   @LazyCollection(LazyCollectionOption.EXTRA)
   private Set<Employee> employees = new HashSet<Employee>();

}

그리고 director에 작업을 추가하려면 다음과 같은 코드를 작성해야 합니다.

Employee director = session.find(Employee.class, 4);
EmployeeTask task = session.find(EmployeeTask.class, 101);
task.employees.add(director);

session.update(task);
session.flush();

따라서 Task 클래스의 직원 필드에 LazyCollectionOption.EXTRA 주석이 있는 경우 직원 컬렉션(Task 클래스)과 작업 컬렉션(Employee 클래스)은 데이터베이스에서 전혀 로드되지 않습니다 .

이 코드가 실행되면 Employee_task 서비스 테이블에 하나의 레코드만 삽입됩니다. 기억하듯이 다음과 같습니다.

employee_task 테이블 :
employee_id task_id
1 1
2 2
5
5 4
5 5
4 7
6 8
4 101

추가된 줄은 녹색으로 강조 표시됩니다. 이 줄을 추가하기 위해 데이터베이스에서 컬렉션을 로드할 필요가 없습니다. Hibernate는 그것 없이도 할 것입니다. 이것이 바로 LazyCollectionOption.EXTRA가 데이터베이스 작업 속도를 크게 높이는 경우입니다.

N+1 문제

그러나 물론 이 모드에도 단점이 있습니다. 예를 들어 LazyCollectionOption.EXTRA 주석은 N+1 문제를 생성합니다 .

사용자의 모든 댓글을 검토하기로 결정한 경우:

User user = session.load(User.class, 1);
List<Comment> comments = user.getComments();
for (Comment comment : comments) {
    System.out.println(comment);
}

그런 다음 Hibernate는 각 Comment 개체에 대한 별도의 요청에서 실행됩니다. 또한 모든 댓글 수를 가져오는 추가 쿼리가 하나 더 있습니다. 이로 인해 코드 속도가 상당히 느려질 수 있습니다.

당신의 사용자가 1000개의 코멘트를 가지고 있다면, Hibernate는 이 코드를 실행하기 위해 데이터베이스에 1001개의 쿼리를 만들 것이다. 이 클래스의 모든 개체가 필요하다는 것을 미리 알고 있다면.