Lernen Sie LazyCollectionOption.EXTRA kennen

Von größtem Interesse ist jedoch der Wert LazyCollectionOption.EXTRA. Wenn Sie ihn als Wert der Annotation @LazyCollection angeben , verzögert Hibernate das Laden der Elemente der Sammlung so lange wie möglich.

Wenn Sie versuchen, die Anzahl der Elemente in einer Sammlung zu ermitteln:

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

Dann führt Hibernate für diesen gesamten Code nur eine Abfrage aus:

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

Wenn Sie jedoch einen Kommentar aus der Sammlung erhalten möchten, zum Beispiel Nummer 3:

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

Dann stellt sich die Frage: Woher soll Hibernate wissen, dass das Element das dritte ist, ohne alle Elemente in den Speicher zu laden?

Um dieses Problem zu lösen, wird vorgeschlagen, eine zusätzliche Spalte in der Kommentartabelle zu erstellen, in der die Ordnungszahl des Kommentars in der Kommentarsammlung gespeichert wird. Und auch hierfür benötigen Sie eine spezielle Annotation – @OrderColumn .

So würde diese Lösung aussehen:

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

Der Hauptvorteil von LazyCollectionOption.EXTRA

Wir sehen den größten Vorteil von LazyCollectionOption.EXTRA, wenn wir es mit der Annotation @ManyToMany angeben . Nehmen wir unseren alten Fall, in dem wir einen Mitarbeiter und eine Aufgabe haben und einem Benutzer viele Aufgaben zuweisen können.

Unsere Java-Klassen sehen so aus:

Mitarbeiterklasse :

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

}

Und die EmployeeTask-Klasse :

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

}

Und um dem Direktor eine Aufgabe hinzuzufügen, müssen Sie etwa diesen Code schreiben:

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

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

Wenn also das Feld „Mitarbeiter“ in der Klasse „Task“ die Annotation „LazyCollectionOption.EXTRA“ hat, werden die Sammlung „Mitarbeiter“ (der Klasse „Task“) und die Sammlung „Aufgaben“ (der Klasse „Mitarbeiter“) niemals aus der Datenbank geladen .

Wenn dieser Code ausgeführt wird, wird nur ein Datensatz in die Diensttabelle „employee_task“ eingefügt, der, wie Sie sich erinnern, etwa so aussieht:

Employee_task-Tabelle :
Angestellten ID task_id
1 1
2 2
5 3
5 4
5 5
4 7
6 8
4 101

Die hinzugefügte Zeile wird grün hervorgehoben. Um diese Zeile hinzuzufügen, müssen Sie keine Sammlungen aus der Datenbank laden – Hibernate kommt ohne sie aus. Dies ist genau dann der Fall, wenn LazyCollectionOption.EXTRA die Arbeit mit der Datenbank erheblich beschleunigt.

N+1-Problem

Aber dieser Modus hat natürlich auch eine Kehrseite. Beispielsweise generiert die Annotation LazyCollectionOption.EXTRA ein N+1 Problem .

Wenn Sie sich entscheiden, alle Kommentare Ihres Benutzers durchzugehen:

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

Dann wird Hibernate für jedes Kommentarobjekt eine separate Anfrage ausführen. Und noch eine weitere Abfrage, um die Anzahl aller Kommentare zu ermitteln. Dies kann den Code erheblich verlangsamen.

Wenn Ihr Benutzer 1.000 Kommentare hat, führt Hibernate 1.001 Abfragen an die Datenbank durch, um diesen Code auszuführen, es könnte jedoch auch einer reichen. Wenn Sie im Voraus wüssten, dass Sie alle Objekte dieser Klasse benötigen würden.