Hibernate Lazy Loading
O Hibernate é o rei do ORM no mundo Java, e o Lazy Loading (Carregamento Preguiçoso) é uma de suas funcionalidades mais amadas e odiadas. Se você já viu uma LazyInitializationException no seu log, este post é para você.
Performance por Omissão
Imagine que você tem uma classe User que tem uma lista de 10.000 Order. Se toda vez que você buscasse um usuário o Hibernate buscasse também todos os seus pedidos, sua aplicação ficaria lenta e o banco de dados sobrecarregado. O Lazy Loading resolve isso não buscando os dados até que você realmente precise deles.
Como funciona o “Truque” do Proxy
O Hibernate não coloca null na sua lista quando ela é Lazy. Ele coloca um Proxy (um impostor).
1
2
3
4
5
6
7
8
9
@Entity
public class User {
@OneToMany(fetch = FetchType.LAZY)
private List<Order> orders;
}
// No código:
User user = repository.findById(1L); // O Hibernate busca o User, mas não as Orders.
// A lista 'orders' aqui é um Proxy (HibernateProxy).
Quando você faz user.getOrders().size(), o Proxy intercepta a chamada, percebe que os dados ainda não estão lá, e dispara uma nova query no banco de dados para buscar os pedidos. Isso é chamado de Lazy Initialization.
O Terror: LazyInitializationException
O segredo é que o Proxy precisa de uma Sessão do Hibernate (Session/EntityManager) ativa para falar com o banco. Se você tentar acessar a lista após a transação ter fechado (ex: dentro do seu Controller ou após o @Transactional), você terá um erro:
1
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
Como Resolver (Do Jeito Certo)
- Join Fetch (JPQL/Criteria): Informe ao Hibernate que, naquela consulta específica, você quer trazer os filhos de uma vez (Eager).
1
SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id
- Entity Graph: Uma forma mais elegante e programática de definir o que deve ser carregado.
- DTOs: Busque apenas os dados necessários e mapeie para um objeto simples (POJO), evitando carregar entidades inteiras.
Curiosidade: O Problema do N+1
O Lazy Loading é o culpado número 1 pelo problema do N+1 queries. Se você buscar 100 usuários e, em um loop, acessar os pedidos de cada um, o Hibernate fará 1 query para os usuários e 100 queries adicionais para os pedidos. Sempre monitore seus logs de SQL!
Próximos Passos: Dominando a Performance
Entender o Lazy Loading é apenas o primeiro passo para dominar a persistência de dados. Agora que você sabe como o Hibernate evita carregar dados desnecessários, que tal aprofundar no oposto? No próximo post, vamos explorar o Problema do N+1 e como o JOIN FETCH resolve gargalos de performance de forma definitiva, garantindo que sua aplicação escale sem sufocar o banco de dados.