Sobes.tech
Junior — Middle

Explique por que pode ocorrer um problema N+1 ao executar os métodos UserRepository.findById() e User.getEmails().forEach() se o método getUsers() estiver marcado como @Transactional e o campo email estiver anotado como @OneToMany.

sobes.tech IA

Resposta da IA

O problema N+1 ocorre devido ao carregamento preguiçoso das relações no JPA. No seu caso:

  • O método UserRepository.findById() carrega o usuário.
  • O campo emails está marcado como @OneToMany, com o carregamento padrão preguiçoso (FetchType.LAZY).
  • Ao chamar User.getEmails().forEach(), para cada usuário, uma consulta separada ao banco de dados é feita para carregar seus emails.

Se o método getUsers() estiver marcado como @Transactional, a sessão está aberta e as coleções preguiçosas podem ser carregadas ao acessá-las. Mas se você percorrer a lista de usuários e chamar getEmails() para cada um, haverá 1 consulta para os usuários + N consultas para os emails — daí o N+1.

Para evitar isso, você pode usar:

  • JOIN FETCH em JPQL para carregar previamente as coleções.
  • Alterar a estratégia de carregamento para EAGER (com cautela).
  • Usar Entity Graphs.

Exemplo com JOIN FETCH:

@Query("SELECT u FROM User u JOIN FETCH u.emails WHERE u.id = :id")
User findByIdWithEmails(@Param("id") Long id);