Lär känna LazyCollectionOption.EXTRA

Men av största intresse är LazyCollectionOption.EXTRA-värdet. Om du anger det som värdet för @LazyCollection -kommentaren , kommer Hibernate att fördröja laddningen av elementen i samlingen så länge som möjligt.

Om du försöker få antalet element i en samling:

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

Sedan kommer Hibernate endast att köra en fråga för all denna kod:

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

Men om du vill få en kommentar från samlingen, till exempel nummer 3:

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

Då uppstår frågan: hur ska Hibernate veta att elementet är det tredje utan att ladda alla element i minnet?

För att lösa detta problem föreslås det att man gör en extra kolumn i kommentarstabellen, som kommer att lagra kommentarens ordningsnummer i samlingen av kommentarer. Och även för detta behöver du en speciell anteckning - @OrderColumn .

Så här skulle den lösningen se ut:

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

Den största fördelen med LazyCollectionOption.EXTRA

Vi ser den starkaste fördelen med LazyCollectionOption.EXTRA när vi specificerar det med @ManyToMany -kommentaren . Låt oss ta vårt gamla fall där vi har en anställd, en uppgift och vi kan tilldela många uppgifter till en användare.

Våra Java-klasser ser ut så här:

Anställd klass :

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

}

Och klassen 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>();

}

Och för att lägga till en uppgift till regissören måste du skriva något i stil med denna kod:

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

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

Så om anställdas fält i klassen Task har anteckningen LazyCollectionOption.EXTRA, kommer anställdas samling (av Task-klassen) och uppgiftssamlingen (av klassen Employee) aldrig att laddas från databasen alls .

När den här koden exekveras kommer endast en post att infogas i tjänstetabellen werknemer_task, som, som ni minns, ser ut ungefär så här:

anställd_uppgiftstabell :
Anställnings-ID uppgifts-id
1 1
2 2
5 3
5 4
5 5
4 7
6 8
4 101

Den tillagda raden är markerad i grönt. För att lägga till den här raden behöver du inte ladda samlingar från databasen - Hibernate klarar sig utan den. Detta är precis fallet när LazyCollectionOption.EXTRA påskyndar arbetet med databasen avsevärt.

N+1 problem

Men det här läget har förstås också en baksida. Till exempel genererar LazyCollectionOption.EXTRA-anteckningen ett N+1-problem .

Om du bestämmer dig för att gå igenom alla dina användares kommentarer:

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

Då kör Hibernate på en separat begäran för varje kommentarobjekt. Och även ytterligare en fråga för att få räkningen av alla kommentarer. Detta kan avsevärt sakta ner koden.

Om din användare har 1000 kommentarer kommer Hibernate att göra 1001 frågor till databasen för att exekvera den här koden, även om det skulle kunna göras med en. Om du visste i förväg att du skulle behöva alla föremål i den här klassen.