Junior — Middle
Vysvetlite, prečo môže pri vykonávaní metód UserRepository.findById() a User.getEmails().forEach() dôjsť k problému N+1, ak je metóda getUsers() označená ako @Transactional a pole email je anotované ako @OneToMany.
sobes.tech AI
Odpoveď od AI
Problém N+1 vzniká kvôli lenivému načítaniu vzťahov v JPA. Vo vašom prípade:
- Metóda
UserRepository.findById()načítava používateľa. - Pole
emailsje označené ako@OneToMany, predvolené načítanie je lenivé (FetchType.LAZY). - Pri volaní
User.getEmails().forEach()pre každého používateľa sa vykoná samostatný dotaz do databázy na načítanie jeho emailov.
Ak je metóda getUsers() označená ako @Transactional, je session otvorená a lenivé kolekcie môžu byť načítané pri prístupe. Ale ak prechádzate zoznam používateľov a pre každého voláte getEmails(), bude 1 dotaz na používateľov + N dotazov na emaily — odtiaľ problém N+1.
Aby ste tomu zabránili, môžete použiť:
JOIN FETCHv JPQL na predbežné načítanie kolekcií.- Zmeniť stratégiu načítania na
EAGER(s opatrnosťou). - Používať Entity Graphs.
Príklad s JOIN FETCH:
@Query("SELECT u FROM User u JOIN FETCH u.emails WHERE u.id = :id")
User findByIdWithEmails(@Param("id") Long id);