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개의 쿼리를 만들 것이다. 이 클래스의 모든 개체가 필요하다는 것을 미리 알고 있다면.
GO TO FULL VERSION