A LazyCollectionOption.EXTRA megismerése

De a legérdekesebb a LazyCollectionOption.EXTRA érték. Ha ezt a @LazyCollection annotáció értékeként adja meg , akkor a Hibernate a lehető legtovább késlelteti a gyűjtemény elemeinek betöltését.

Ha megpróbálja lekérni a gyűjtemény elemeinek számát:

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

Ekkor a Hibernate az összes kódra csak egy lekérdezést hajt végre:

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

Ha azonban egy megjegyzést szeretne kapni a gyűjteményből, például a 3. számot:

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

Ekkor felmerül a kérdés: honnan kellene tudnia a Hibernate-nak, hogy az elem a harmadik anélkül, hogy az összes elemet a memóriába töltené?

A probléma megoldására javasolt egy további oszlop létrehozása a megjegyzéstáblázatban, amely a megjegyzés sorszámát tárolja a megjegyzésgyűjteményben. És ehhez is szükség van egy speciális megjegyzésre - @OrderColumn .

Így nézne ki a megoldás:

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

A LazyCollectionOption.EXTRA fő előnye

A LazyCollectionOption.EXTRA legerősebb előnyét akkor látjuk, ha a @ManyToMany annotációval adjuk meg . Vegyük a régi esetünket, ahol van egy alkalmazottunk, egy feladatunk, és egy felhasználóhoz sok feladatot rendelhetünk.

Java osztályaink így néznek ki:

Alkalmazotti osztály :

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

}

És az EmployeeTask osztály :

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

}

És ahhoz, hogy feladatot adjon a rendezőhöz, valami ehhez hasonló kódot kell írnia:

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

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

Tehát, ha a Task osztályban az alkalmazottak mezője rendelkezik a LazyCollectionOption.EXTRA megjegyzéssel, akkor az alkalmazottak gyűjteménye (a Task osztályban) és a feladatgyűjtemény (az Employee osztályban) soha nem töltődik be az adatbázisból .

Amikor ez a kód lefut, csak egy rekord kerül beillesztésre a munkavállalói_feladat szolgáltatási táblába, amely, mint emlékszel, valahogy így néz ki:

munkavállaló_feladat táblázat :
munkavállalói azonosító feladat_azonosítója
1 1
2 2
5 3
5 4
5 5
4 7
6 8
4 101

A hozzáadott sor zöld színnel van kiemelve. Ennek a sornak a hozzáadásához nem kell gyűjteményeket betöltenie az adatbázisból - a Hibernate megteszi ezt nélküle. Pontosan ez az eset, amikor a LazyCollectionOption.EXTRA nagymértékben felgyorsítja az adatbázissal végzett munkát.

N+1 probléma

De persze ennek a módnak van egy árnyoldala is. Például a LazyCollectionOption.EXTRA annotáció N+1 problémát generál .

Ha úgy dönt, hogy végignézi felhasználói megjegyzéseit:

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

Ezután a hibernálás külön kérésre fog végrehajtani minden egyes megjegyzés objektumhoz. És még egy további lekérdezés az összes megjegyzés számának megtekintéséhez. Ez jelentősen lelassíthatja a kódot.

Ha a felhasználónak 1000 megjegyzése van, akkor a Hibernate 1001 lekérdezést hajt végre az adatbázisban, hogy végrehajtsa ezt a kódot, bár eggyel is megteheti. Ha előre tudtad, hogy szükséged lesz ennek az osztálynak az összes objektumára.