Pagkilala sa LazyCollectionOption.EXTRA

Ngunit ang pinakamalaking interes ay ang LazyCollectionOption.EXTRA na halaga. Kung tutukuyin mo ito bilang ang halaga ng @LazyCollection annotation , pagkatapos ay maaantala ng Hibernate ang paglo-load ng mga elemento ng koleksyon hangga't maaari.

Kung susubukan mong kunin ang bilang ng mga elemento sa isang koleksyon:

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

Pagkatapos para sa lahat ng code na ito, ang Hibernate ay magpapatupad lamang ng isang query:

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

Gayunpaman, kung gusto mong makakuha ng isang komento mula sa koleksyon, halimbawa numero 3:

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

Pagkatapos ay lumitaw ang tanong: paano malalaman ng Hibernate na ang elemento ay ang pangatlo nang hindi nilo-load ang lahat ng mga elemento sa memorya?

Upang malutas ang problemang ito, iminungkahi na gumawa ng karagdagang column sa talahanayan ng komento, na mag-iimbak ng ordinal na numero ng komento sa koleksyon ng mga komento. At para din dito kailangan mo ng isang espesyal na anotasyon - @OrderColumn .

Narito kung ano ang magiging hitsura ng solusyon na iyon:

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

Ang pangunahing bentahe ng LazyCollectionOption.EXTRA

Nakikita namin ang pinakamalakas na bentahe ng LazyCollectionOption.EXTRA kapag tinukoy namin ito kasama ang @ManyToMany annotation . Kunin natin ang ating lumang kaso kung saan mayroon tayong Empleyado, isang Gawain, at maaari tayong magtalaga ng maraming gawain sa isang user.

Ang aming mga klase sa Java ay ganito ang hitsura:

Klase ng empleyado :

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

}

At ang klase ng 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>();

}

At upang magdagdag ng isang gawain sa direktor, kailangan mong magsulat ng isang bagay tulad ng code na ito:

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

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

Kaya, kung ang field ng mga empleyado sa klase ng Task ay may LazyCollectionOption.EXTRA annotation, ang koleksyon ng mga empleyado (ng klase ng Task) at ang koleksyon ng gawain (ng Employee class) ay hindi kailanman mailo-load mula sa database .

Kapag ang code na ito ay naisakatuparan, isang tala lamang ang ilalagay sa employee_task service table, na, gaya ng naaalala mo, ay ganito ang hitsura:

talahanayan ng empleyado_task :
employee_id task_id
1 1
2 2
5 3
5 4
5 5
4 7
6 8
4 101

Ang idinagdag na linya ay naka-highlight sa berde. Upang idagdag ang linyang ito, hindi mo kailangang mag-load ng mga koleksyon mula sa database - Magagawa ng Hibernate nang wala ito. Ito ang eksaktong kaso kapag ang LazyCollectionOption.EXTRA ay lubos na nagpapabilis sa trabaho sa database.

N+1 na problema

Ngunit, siyempre, ang mode na ito ay mayroon ding downside. Halimbawa, ang LazyCollectionOption.EXTRA annotation ay bumubuo ng N+1 Problem .

Kung magpasya kang suriin ang lahat ng komento ng iyong user:

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

Pagkatapos ay isasagawa ang Hibernate sa isang hiwalay na kahilingan para sa bawat object ng Komento. At isa pang karagdagang query para makuha ang bilang ng lahat ng komento. Ito ay maaaring makabuluhang pabagalin ang code.

Kung ang iyong user ay may 1000 komento, ang Hibernate ay gagawa ng 1001 na mga query sa database upang isagawa ang code na ito, bagama't maaari itong gawin sa isa. Kung alam mo nang maaga na kakailanganin mo ang lahat ng mga bagay ng klase na ito.