Lazy/Eager - Carregamento de Entidades utilizando JPA com SpringBoot
Tags: braziliandevs, java
Published: 2022-05-11 20:44:19


Um dos pontos mais importante na construção de um software é a performance, portanto entender as queries e otimizá-las ao máximo que puder pode resultar num belo ganho de desempenho.

Partindo dessa premissa e por mais que utilizamos frameworks como SpringBoot que otimizam todo esse processo  entender o funcionamento do lazy e do eager da JPA(Java Persistence API) é fundamental para o desempenho de um APP, pois o uso de maneira errada pode resultar em grandes perdas de performance e forçar a aplicação a realizar diversas queries desnecessárias no banco de dados (podendo ocasionar assim o tão famoso problema das N+1 consultas).



**Lazy - Carregamento Preguiçoso**

Vamos começar nossos estudos entendendo o lazy que é o carregamento default da JPA quando você não especifica nada. O lazy não faz o carregamento de determinados objetos até que você precise deles(daí vem a tradução de preguiçoso) ele ocorre quando temos entidades associadas para muitos isto é quando temos algum relacionamento OneToMany na nossa entidade.

**Eager - Carregamento Ansioso/Guloso**

Oposto ao Lazy o eager ja traz do banco os objetos mesmo que você não vá utiliza-los, ele ocorre quando temos entidade associadas para um, isto é quando temos algum relacionamento ManyToOne na nossa entidade.

**Exemplificando**

Vamos supor que no meu domínio de negócio eu tenho duas classes que se relacionam da seguinte maneira:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bha69usmx2jqpu0sgneo.png)

Reparem que no exemplo acima eu tenho um relacionamento um-para-muitos, já que um team pode conter muitos palyers e muitos players podem pertencer a um time.

Pelo padrão da JPA quando eu busco um Player a JPA  já traz do banco o team  ao qual ele pertence(Eager), já quando eu busco o team a JPA não traz do banco os jogadores pertencentes ao time (Lazy)
	
**Vendo o Funcionamento na Pratica o Funcionamento do Eager**

Para vermos como isso ocorre na pratica construí uma API com base no modelo apresentado acima(o link do projeto no GitHub estará ao final do artigo).

Na minha API tenho as seguinte classes mapeadas:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0z25mjdfjj87f4gjtqbg.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hf43dgkiqne58veobsrh.png)

No pacote Resource da minha API eu criei um controller com a seguinte  configuração:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rpsusg0jxs1tncxxxgho.png)

Reparem que nesse controller eu chamo um service que irá buscar os dados do player pelo id e do resultado jogo num DTO que eu chamei PlayerDTO, portanto quando faço pelo browser/Postman/Insonia a seguinte chamada  (localhost:8080/player/1) a API retorna os seguintes dados do player:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vexjde3xwpdryq4n440p.PNG)

Bem se habilitarmos o sql lá no nosso application.properties, para vermos as queries que a API faz lá no console veremos o seguinte detalhe:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y5xkutfknc1ljiw7tv82.PNG)

Vejam que mesmo não precisando dos dados do team a JPA faz um join (desnecessário nesse caso já que eu só quero os dados do player) na minha tabela team conforme destacado em amarelo, já que como vimos acima por padrão toda vez que a entidade  tem uma associação para um o carregamento e eager.

Agora você deve se está se perguntando então como eu faço para customizar essa busca, isto é quero evitar esse join desnecessário?

Bem uma forma e você definir um fetch na mão(muita cautela ao fazer isso pois você pode estar piorando a performance em outros endpoints dependendo do contexto do negócio) da seguinte maneira:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c1e06q2cip2qhvessbqa.png)

Ao rodarmos a consulta novamente veremos na console a seguinte query:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ebwp6ltg6d93vvjmy6ql.PNG)

Reparem que desta vez ele não fez join la na minha tabela team e tudo funcionou de boa.

**Vendo o Funcionamento na Prática do Lazy**

Continuando no estudo da nossa API vamos vê agora o funcionamento do Lazy, para isto no meu pacote resource criei o seguinte controller

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rp6060cyacoe21ngwi9m.png)

Reparem que nesse controller eu chamo um service que irá buscar os dados do team pelo id e do resultado jogo num DTO que eu chamei TeamDTO, portanto quando faço pelo browser/Postman/Insonia a seguinte chamada  (localhost:8080/team/1) a API retorna os seguintes dados do team:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w62xnjsuy5vm3yna0rae.PNG)

Agora se dermos uma olhada novamente no console veremos as seguintes queries:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/davfssrvfz0cmxo90srj.PNG)

Reparem que quando executamos essa chamada o JPA faz duas queries na primeira ele busca os dados do player e na segunda de team.
Bem agora você deve esta se fazendo uma outra pergunta, Ué mas como ele fez essa mágica?

Isso só ocorreu pois lá no TeamService eu faço a seguinte chamada conforme vemos abaixo:

result.get().getPlayers()

O getPlayers() que usei disparou outra consulta no banco para buscar os dados do player. Portanto  conforme vimos acima por padrão toda vez que a entidade  tem uma associação para muitos o carregamento é Lazy(preguiçoso) a JPA não traz o objeto até que você precise dele.

**Considerações Finais**

O objetivo deste artigo foi justamente apresentar aos leitores os conceitos do Fetch/Eager tão utilizados na JPA. O bom entendimento desses conceitos pode acarretar em ganhos de performance na sua aplicação desde que você adote a melhor prática baseado no seu modelo de negócio.

**Links/Referencias Bibliográficas**

Repositório do Git da demo: https://github.com/rmarinheiro/demolazyeager

https://www.baeldung.com/hibernate-lazy-eager-loading