Cunoașterea LazyCollectionOption.EXTRA

Dar de cel mai mare interes este valoarea LazyCollectionOption.EXTRA. Dacă o specificați ca valoare a adnotării @LazyCollection , atunci Hibernate va întârzia încărcarea elementelor colecției cât mai mult posibil.

Dacă încercați să obțineți numărul de elemente dintr-o colecție:

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

Apoi, pentru tot acest cod, Hibernate va executa o singură interogare:

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

Cu toate acestea, dacă doriți să obțineți un comentariu din colecție, de exemplu numărul 3:

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

Atunci apare întrebarea: cum ar trebui Hibernate să știe că elementul este al treilea fără a încărca toate elementele în memorie?

Pentru a rezolva această problemă, se propune realizarea unei coloane suplimentare în tabelul de comentarii, care va stoca numărul ordinal al comentariului în colecția de comentarii. Și, de asemenea, pentru aceasta aveți nevoie de o adnotare specială - @OrderColumn .

Iată cum ar arăta soluția:

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

Principalul avantaj al LazyCollectionOption.EXTRA

Vedem cel mai puternic avantaj al LazyCollectionOption.EXTRA atunci când îl specificăm cu adnotarea @ManyToMany . Să luăm cazul nostru vechi în care avem un angajat, o sarcină și putem atribui multe sarcini unui singur utilizator.

Clasele noastre Java arată astfel:

Clasa de angajati :

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

}

Și clasa 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>();

}

Și pentru a adăuga o sarcină directorului, trebuie să scrieți ceva ca acest cod:

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

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

Deci, dacă câmpul angajați din clasa Task are adnotarea LazyCollectionOption.EXTRA, atunci colecția de angajați (a clasei Task) și colecția de sarcini (a clasei Employee) nu vor fi încărcate deloc din baza de date .

Când acest cod este executat, o singură înregistrare va fi inserată în tabelul de serviciu employee_task, care, după cum vă amintiți, arată cam așa:

tabelul de sarcini_egajați :
card de identitate al angajatului task_id
1 1
2 2
5 3
5 4
5 5
4 7
6 8
4 101

Linia adăugată este evidențiată în verde. Pentru a adăuga această linie, nu trebuie să încărcați colecții din baza de date - Hibernate se va descurca fără ea. Acesta este exact cazul când LazyCollectionOption.EXTRA accelerează foarte mult lucrul cu baza de date.

N+1 problemă

Dar, desigur, acest mod are și un dezavantaj. De exemplu, adnotarea LazyCollectionOption.EXTRA generează o problemă N+1 .

Dacă decideți să parcurgeți toate comentariile utilizatorului dvs.:

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

Apoi Hibernate se va executa la o cerere separată pentru fiecare obiect Comentariu. Și, de asemenea, încă o interogare suplimentară pentru a obține numărul tuturor comentariilor. Acest lucru poate încetini semnificativ codul.

Dacă utilizatorul dvs. are 1000 de comentarii, atunci Hibernate va face 1001 de interogări la baza de date pentru a executa acest cod, deși ar putea face cu unul. Dacă ai ști dinainte că vei avea nevoie de toate obiectele acestei clase.