Làm quen với LazyCollectionOption.EXTRA

Nhưng quan tâm nhất là giá trị LazyCollectionOption.EXTRA. Nếu bạn chỉ định nó làm giá trị của chú thích @LazyCollection thì Hibernate sẽ trì hoãn việc tải các thành phần của bộ sưu tập càng lâu càng tốt.

Nếu bạn cố lấy số phần tử trong một bộ sưu tập:

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

Sau đó, đối với tất cả mã này, Hibernate sẽ chỉ thực hiện một truy vấn:

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

Tuy nhiên, nếu bạn muốn lấy 1 comment từ bộ sưu tập, ví dụ số 3:

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

Sau đó, câu hỏi đặt ra: làm thế nào Hibernate được cho là biết phần tử đó là phần tử thứ ba mà không cần tải tất cả các phần tử vào bộ nhớ?

Để giải quyết vấn đề này, người ta đề xuất tạo một cột bổ sung trong bảng nhận xét, cột này sẽ lưu trữ số thứ tự của nhận xét trong tập hợp các nhận xét. Và đối với điều này, bạn cần một chú thích đặc biệt - @OrderColumn .

Đây là giải pháp đó sẽ như thế nào:

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

Ưu điểm chính của LazyCollectionOption.EXTRA

Chúng tôi thấy lợi thế mạnh nhất của LazyCollectionOption.EXTRA khi chúng tôi chỉ định nó bằng chú thích @ManyToMany . Hãy xem trường hợp cũ của chúng ta khi chúng ta có một Nhân viên, một Nhiệm vụ và chúng ta có thể giao nhiều nhiệm vụ cho một người dùng.

Các lớp Java của chúng tôi trông như thế này:

Hạng nhân viên :

@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>();

}

lớp 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>();

}

Và để thêm một nhiệm vụ cho giám đốc, bạn cần viết một cái gì đó giống như mã này:

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

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

Vì vậy, nếu trường nhân viên trong lớp Nhiệm vụ có chú thích LazyCollectionOption.EXTRA, thì tập hợp nhân viên (của lớp Nhiệm vụ) và tập hợp nhiệm vụ (của lớp Nhân viên) sẽ không bao giờ được tải từ cơ sở dữ liệu .

Khi mã này được thực thi, chỉ một bản ghi sẽ được chèn vào bảng dịch vụ employee_task, như bạn nhớ, trông giống như sau:

bảng employee_task :
Mã hiệu công nhân task_id
1 1
2 2
5 3
5 4
5 5
4 7
6 số 8
4 101

Dòng đã thêm được đánh dấu bằng màu xanh lá cây. Để thêm dòng này, bạn không cần tải các bộ sưu tập từ cơ sở dữ liệu - Hibernate sẽ làm được nếu không có nó. Đây chính xác là trường hợp khi LazyCollectionOption.EXTRA tăng tốc đáng kể công việc với cơ sở dữ liệu.

Vấn đề N+1

Nhưng, tất nhiên, chế độ này cũng có nhược điểm. Ví dụ: chú thích LazyCollectionOption.EXTRA tạo ra N+1 Vấn đề .

Nếu bạn quyết định xem qua tất cả các nhận xét của người dùng:

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

Sau đó, Hibernate sẽ thực hiện theo một yêu cầu riêng cho từng đối tượng Nhận xét. Và cũng có thêm một truy vấn nữa để có được số lượng tất cả các bình luận. Điều này có thể làm chậm đáng kể mã.

Nếu người dùng của bạn có 1000 nhận xét, thì Hibernate sẽ thực hiện 1001 truy vấn tới cơ sở dữ liệu để thực thi mã này, mặc dù nó có thể thực hiện với một. Nếu bạn biết trước rằng bạn sẽ cần tất cả các đối tượng của lớp này.