Carregamento ansioso/preguiçoso no Hibernate

Eager/Lazy Loading In Hibernate

1. Introdução

Ao trabalhar com um ORM, a busca / carregamento de dados pode ser classificada em dois tipos: ansioso e preguiçoso.

Neste artigo rápido, mostraremos as diferenças e mostraremos que elas podem ser usadas no Hibernate.

2. Dependências do Maven

Para usar o Hibernate, vamos primeiro definir a dependência principal em nossopom.xml:


    org.hibernate
    hibernate-core
    5.2.2.Final

A última versão do Hibernate pode ser encontradahere.

3. Carregamento ansioso e preguiçoso

A primeira coisa que devemos discutir aqui é o que carregamento lento e carregamento ansioso são:

  • Eager Loading é um padrão de design no qual a inicialização de dados ocorre no local

  • Lazy Loading é um padrão de design que é usado para adiar a inicialização de um objeto, contanto que seja possível

Vamos ver como isso realmente funciona com alguns exemplos:

A classeUserLazy:

@Entity
@Table(name = "USER")
public class UserLazy implements Serializable {

    @Id
    @GeneratedValue
    @Column(name = "USER_ID")
    private Long userId;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
    private Set orderDetail = new HashSet();

    // standard setters and getters
    // also override equals and hashcode

}

A classeOrderDetail:

@Entity
@Table (name = "USER_ORDER")
public class OrderDetail implements Serializable {

    @Id
    @GeneratedValue
    @Column(name="ORDER_ID")
    private Long orderId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="USER_ID")
    private UserLazy user;

    // standard setters and getters
    // also override equals and hashcode

}

UmUser pode ter váriosOrderDetails. In eager loading strategy, if we load the User data, it will also load up all orders associated with it and will store it in a memory.

Mas, quando o carregamento lento está ativado, se extrairmos umUserLazy, os dados deOrderDetail não serão inicializados e carregados em uma memória até que uma chamada explícita seja feita a eles.

Na próxima seção, veremos como o exemplo acima é implementado no Hibernate.

4. Carregando configuração

Nesta seção, veremos como podemos configurar estratégias de busca no Hibernate. Reutilizaremos exemplos da seção anterior.

O carregamento lento pode ser simplesmente ativado usando o seguinte parâmetro de anotação:

fetch = FetchType.LAZY

Para usar o Eager Fetching, o seguinte parâmetro é usado:

fetch = FetchType.EAGER

Para configurar o Eager Loading, usamos a classe gêmea deUserLazy chamadaUserEager.

Na próxima seção, veremos as diferenças entre os dois tipos de busca.

5. Diferenças

Como mencionamos, a principal diferença entre os dois tipos de busca é um momento em que os dados são carregados na memória.

Vejamos este exemplo:

List users = sessionLazy.createQuery("From UserLazy").list();
UserLazy userLazyLoaded = users.get(3);
return (userLazyLoaded.getOrderDetail());

Com a abordagem de inicialização lenta,orderDetailSet será inicializado apenas quando for explicitamente chamado usando um getter ou algum outro método, conforme mostrado no exemplo acima:

UserLazy userLazyLoaded = users.get(3);

Mas com uma abordagem rápida emUserEager, ele será inicializado imediatamente na primeira linha do exemplo acima:

List user = sessionEager.createQuery("From UserEager").list();

Para carregamento lento, um objeto proxy é usado e uma consulta SQL separada é disparada para carregar oorderDetailSet.

A idéia de desativar proxies ou carregamento lento é considerada uma prática ruim no Hibernate. Isso pode resultar em muitos dados sendo buscados em um banco de dados e armazenados na memória, independentemente da necessidade.

O método a seguir pode ser usado para testar a funcionalidade acima:

Hibernate.isInitialized(orderDetailSet);

Agora é importante dar uma olhada nas consultas que são geradas nos dois casos:

true

A configuração acima emfetching.hbm.xml mostra as consultas SQL que são geradas. Se você observar uma saída do console, poderá ver as consultas geradas.

Para Lazy Loading, a consulta gerada para carregar os dadosUser:

select user0_.USER_ID as USER_ID1_0_,  ... from USER user0_

No entanto, no carregamento antecipado, vimos uma junção sendo feita comUSER_ORDER:

select orderdetai0_.USER_ID as USER_ID4_0_0_, orderdetai0_.ORDER_ID as ORDER_ID1_1_0_, orderdetai0_ ...
  from USER_ORDER orderdetai0_ where orderdetai0_.USER_ID=?

A consulta acima é gerada para todos osUsers, o que resulta em muito mais memória sendo usada do que na outra abordagem.

6. Vantagens e desvantagens

6.1. Carregamento lento

Vantagens:

  • Tempo de carregamento inicial muito menor do que na outra abordagem

  • Menos consumo de memória do que na outra abordagem

Desvantagens:

  • A inicialização atrasada pode afetar o desempenho durante momentos indesejados

  • Em alguns casos, você precisa manipular objetos inicializados preguiçosamente com um cuidado especial ou pode acabar com uma exceção

6.2. Carregamento ansioso:

Vantagens:

  • Não há impactos no desempenho relacionados à inicialização atrasada

Desvantagens:

  • Tempo inicial de carregamento longo

  • Carregar muitos dados desnecessários pode afetar o desempenho

7. Carregamento lento em hibernação

Hibernate applies lazy loading approach on entities and associations by providing a proxy implementation de classes.

O Hibernate intercepta chamadas para uma entidade, substituindo-o por um proxy derivado da classe de uma entidade. Em nosso exemplo, quando uma informação solicitada está faltando, ela será carregada de um banco de dados antes que o controle seja cedido para a implementação da classeUser.

Também deve ser observado que quando a associação é representada como uma classe de coleção (nos exemplos acima ela é representada comoSet<OrderDetail> orderDetailSet), então um wrapper é criado e substituído por uma coleção original.

Para saber mais sobre o padrão de design de proxy, você pode consultarhere.

8. Conclusão

Neste artigo, mostramos os exemplos dos dois principais tipos de busca usados ​​no Hibernate.

Para conhecimento de nível avançado, você pode consultar o site oficial do Hibernate. Para obter o código discutido neste artigo, dê uma olhada nesterepository.