LazyCollectionOption.EXTRA leren kennen

Maar van het grootste belang is de LazyCollectionOption.EXTRA-waarde. Als u het opgeeft als de waarde van de @LazyCollection- annotatie , zal Hibernate het laden van de elementen van de collectie zo lang mogelijk vertragen.

Als u het aantal elementen in een verzameling probeert te krijgen:

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

Vervolgens voert Hibernate voor al deze code slechts één query uit:

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

Als u echter één opmerking uit de collectie wilt ontvangen, bijvoorbeeld nummer 3:

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

Dan rijst de vraag: hoe moet Hibernate weten dat het element het derde is zonder alle elementen in het geheugen te laden?

Om dit probleem op te lossen, wordt voorgesteld om een ​​extra kolom in de commentaartabel te maken, die het rangtelwoord van het commentaar in de verzameling commentaren zal opslaan. En ook hiervoor heb je een speciale annotatie nodig - @OrderColumn .

Hier is hoe die oplossing eruit zou zien:

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

Het belangrijkste voordeel van LazyCollectionOption.EXTRA

We zien het sterkste voordeel van LazyCollectionOption.EXTRA wanneer we het specificeren met de @ManyToMany annotatie . Laten we ons oude geval nemen waarin we een werknemer hebben, een taak, en we kunnen veel taken toewijzen aan één gebruiker.

Onze Java-klassen zien er als volgt uit:

Werknemer klasse :

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

}

En de 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>();

}

En om een ​​taak aan de regisseur toe te voegen, moet je zoiets als deze code schrijven:

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

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

Dus als het werknemersveld in de Task-klasse de LazyCollectionOption.EXTRA-annotatie heeft, worden de werknemersverzameling (van de Task-klasse) en de taakverzameling (van de Employee-klasse) helemaal nooit uit de database geladen .

Wanneer deze code wordt uitgevoerd, wordt er slechts één record ingevoegd in de servicetabel employee_task, die er, zoals u zich herinnert, ongeveer zo uitziet:

tabel werknemer_taak :
medewerker_id taak_id
1 1
2 2
5 3
5 4
5 5
4 7
6 8
4 101

De toegevoegde regel is groen gemarkeerd. Om deze regel toe te voegen, hoeft u geen collecties uit de database te laden - Hibernate doet het zonder. Dit is precies het geval wanneer LazyCollectionOption.EXTRA het werk met de database enorm versnelt.

N+1 probleem

Maar deze modus heeft natuurlijk ook een keerzijde. De annotatie LazyCollectionOption.EXTRA genereert bijvoorbeeld een N+1 Problem .

Als u besluit alle opmerkingen van uw gebruiker door te nemen:

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

Vervolgens wordt Hibernate uitgevoerd op een afzonderlijk verzoek voor elk commentaarobject. En ook nog een extra vraag om het aantal reacties te krijgen. Dit kan de code aanzienlijk vertragen.

Als uw gebruiker 1000 opmerkingen heeft, zal Hibernate 1001 query's naar de database maken om deze code uit te voeren, hoewel het met één zou kunnen. Als je van tevoren wist dat je alle objecten van deze klasse nodig zou hebben.