O que é carregamento lento no Hibernate?

178

O que é carregamento lento em Java? Eu não entendo o processo. Alguém pode me ajudar a entender o processo de carregamento lento?

roqueiro
fonte

Respostas:

268

Digamos que você tenha um pai e esse pai tenha uma coleção de filhos. O Hibernate agora pode "carregar preguiçosamente" os filhos, o que significa que na verdade ele não carrega todos os filhos ao carregar o pai. Em vez disso, ele os carrega quando solicitado. Você pode solicitar isso explicitamente ou, e isso é muito mais comum, o hibernate os carregará automaticamente quando você tentar acessar um filho.

O carregamento lento pode ajudar a melhorar significativamente o desempenho, pois muitas vezes você não precisará das crianças e, portanto, elas não serão carregadas.

Também tenha cuidado com o problema n + 1. O Hibernate não carregará todos os filhos quando você acessar a coleção. Em vez disso, ele carregará cada filho individualmente. Ao iterar sobre a coleção, isso causa uma consulta para cada filho. Para evitar isso, você pode enganar a hibernação para carregar todos os filhos simultaneamente, por exemplo, chamando parent.getChildren (). Size ().

Thomas Lötzer
fonte
5
Como alternativa, o Hibernate.initialize (parent.getChildren ()) deve ser usado
HakunaMatata
18
A declaração "ao acessar a coleção ... ela carregará cada filho individualmente" é na verdade completamente imprecisa. Na verdade, é exatamente o oposto. Qualquer desreferência de parent.getChildren () fará com que o Hibernate carregue todos os filhos da coleção em uma consulta db. A menos que você tenha usado a dica muito especial de carregamento "extra preguiçoso". Ou, a menos que você armazene em cache a coleção no cache de segundo nível e os filhos associados também não sejam armazenados em cache.
Steve Ebersole
Oh, Stack Overflow - melhor resposta a ser encontrado na parte inferior da página ;-)
Piotrek Hryciuk
76

"Carregamento lento" significa que uma entidade será carregada somente quando você realmente acessar a entidade pela primeira vez.

O padrão é assim:

public Entity getEntity() {
    if (entity == null) {
        entity = loadEntity();
    }
    return entity;
}

Isso economiza o custo de pré-carregar / pré-carregar todas as entidades em um grande conjunto de dados de antemão, enquanto você afinal não precisa de todas elas.

No Hibernate, você pode configurar para carregar lentamente uma coleção de entidades filhas. O carregamento lento real é feito dentro dos métodos pelos PersistentSetquais o Hibernate usa "sob o capô" para atribuir a coleção de entidades como Set.

Por exemplo

public class Parent {
    private Set<Child> children;

    public Set<Child> getChildren() {
        return children;
    }
}

.

public void doSomething() {
    Set<Child> children = parent.getChildren(); // Still contains nothing.

    // Whenever you call one of the following (indirectly), 
    // Hibernate will start to actually load and fill the set.
    children.size();
    children.iterator();
}
BalusC
fonte
25

Martin Fowler define o padrão Lazy Load em Patterns of Enterprise Application Architecture da seguinte maneira:

Um objeto que não contém todos os dados necessários, mas sabe como obtê-los.

Portanto, ao carregar um determinado objeto, a idéia é não carregar com urgência os objetos relacionados que você não pode usar imediatamente para economizar o custo de desempenho relacionado. Em vez disso, os objetos relacionados serão carregados apenas quando usados.

Esse não é um padrão específico para o acesso a dados e o Hibernate, mas é particularmente útil nesses campos e o Hibernate suporta carregamento lento de associações um para muitos e associações de ponto único (um para um e muitos para um) sob certas condições. A interação lenta é discutida em mais detalhes no capítulo 19 da documentação de referência do Hibernate 3.0.

Pascal Thivent
fonte
15

O carregamento lento predefinido é verdadeiro.O carregamento lento significa que, quando a consulta de seleção é executada, ela não atinge o banco de dados. Ele aguardará a função getter, ou seja, quando solicitamos, ele buscará na base de dados. por exemplo: você é um pai que tem um filho com muitos brinquedos. Mas a questão atual é que sempre que você liga para ele (presumimos que você tenha um menino), ele também vem com todos os seus brinquedos. Agora, esse é um problema, já que você não quer que ele carregue seus brinquedos o tempo todo. Portanto, sendo o pai racional, você segue em frente e define os brinquedos da criança como LAZY. Agora, sempre que você liga para ele, ele vem até você sem seus brinquedos.

Chandresh Solanki
fonte
11

A busca preguiçosa decide se deseja carregar objetos filho enquanto carrega o Objeto Pai. Você precisa fazer essa configuração do respectivo arquivo de mapeamento de hibernação da classe pai. Lazy = true(significa não carregar filho) Por padrão, o carregamento lento dos objetos filhos é verdadeiro.

Certifique-se de que os objetos filho não sejam carregados, a menos que sejam explicitamente invocados no aplicativo chamando o getChild()método parent. Nesse caso, o hibernate emite uma nova chamada de banco de dados para carregar o filho quando getChild()realmente é chamado no objeto Parent.

Mas, em alguns casos, você precisa carregar os objetos filhos quando o pai é carregado. Apenas faça o lazy = false e o hibernate carregará o filho quando o pai for carregado do banco de dados.

Exemplo: Se você possui uma TABELA? EMPREGADO mapeado para o objeto Employee e contém um conjunto de objetos Address. Classe pai: Classe empregado, Classe filho: Classe Endereço

public class Employee { 
private Set address = new HashSet(); // contains set of child Address objects 
public Set getAddress () { 
return address; 
} 
public void setAddresss(Set address) { 
this. address = address; 
} 
} 

No arquivo Employee.hbm.xml

<set name="address" inverse="true" cascade="delete" lazy="false"> 
<key column="a_id" /> 
<one-to-many class="beans Address"/> 
</set> 

Na configuração acima. Se lazy="false": - quando você carrega o objeto Employee, o objeto filho time Address também é carregado e definido como o método setAddresss (). Se você ligar para employee.getAdress (), os dados carregados retornarão. Nenhuma nova chamada ao banco de dados.

Se lazy="true": - Essa é a configuração padrão. Se você não mencionar, hibernar considere preguiçoso = verdadeiro. quando você carrega o objeto Employee, o objeto filho time Address não é carregado. Você precisa de chamada extra para a base de dados para obter objetos de endereço. Se você ligar employee.getAdress(), essa consulta do banco de dados será acionada e retornará resultados. Nova chamada ao banco de dados.

Bhavin Shah
fonte
Empregado e endereço não têm relação pai-filho neste cenário. É um relacionamento "tem um" !
Ram
Isso é agregação, não herança.
Rishi
11

Na linguagem dos leigos, é como se você estivesse fazendo um bolo e precisará de 5 a 10 ingredientes na geladeira. Você tem duas opções, obtenha todos os ingredientes da geladeira e coloque-os na plataforma da cozinha ou traga o item que deseja quando precisar.

Da mesma forma, em um carregamento ansioso, você obtém todas as informações sobre o feijão e suas classes relacionadas (não é uma relação infantil ou é, mas tem um relacionamento, por exemplo, bolo tem farinha, leite, creme etc) e, em caso de carregamento lento, primeiro você traz apenas o identificador e os valores provenientes da mesma tabela (ingredientes necessários que primeiro você precisará em sua tigela em caso de bolo). Todas as informações provenientes de outras tabelas serão buscadas como e quando necessárias / usadas.

Keyur
fonte
8

Carregamento lento? Bem, isso significa simplesmente que os registros filhos não são buscados imediatamente, mas automaticamente assim que você tenta acessá-los.

Steffen
fonte
3

A configuração preguiçosa decide se os objetos filhos devem ser carregados ao carregar o Objeto Pai. Você precisa fazer esta configuração, o respectivo arquivo de mapeamento de hibernação da classe pai. Lazy = true (significa não carregar o filho) Por padrão, o carregamento lento dos objetos filhos é verdadeiro . Isso garante que os objetos filho não sejam carregados, a menos que sejam explicitamente invocados no aplicativo, chamando o método getChild () no pai. Nesse caso, o hibernate emite uma nova chamada de banco de dados para carregar o filho quando getChild () é realmente chamado no pai. object.Mas, em alguns casos, você precisa carregar os objetos filhos quando o pai é carregado. Apenas faça com que preguiçoso = false e o hibernate carregue o filho quando o pai for carregado no banco de dados.Exampleslazy = true (padrão) O filho do endereço da classe User pode ficar preguiçoso se não for necessário com frequência.

Siva Chimpiri
fonte
3

O carregamento lento permite adiar a recuperação da associação ou ter um melhor controle sobre a estratégia de busca.

Ao usar o carregamento do EAGER, você define um plano de busca global que não pode ser substituído no momento da consulta, o que significa que você está limitado a uma decisão tomada ao projetar seu modelo de entidade. A busca do EAGER é um cheiro de código , porque a estratégia de busca é uma política de tempo de consulta e pode diferir de um caso de uso de negócios para outro.

A estratégia de busca é um aspecto muito importante, pois a busca em excesso do EAGER pode causar sérios problemas relacionados ao desempenho.

Vlad Mihalcea
fonte
2

O carregamento lento é um padrão de design comumente usado na programação de computadores para adiar a inicialização de um objeto até o ponto em que é necessário. Pode contribuir para a eficiência na operação do programa, se usado de maneira adequada e apropriada

Wikipedia

Link para carregamento lento do hibernate.org

Diego Dias
fonte
1

Bem, isso significa simplesmente carregar os dados que você precisa atualmente, em vez de carregar um monte de dados de uma só vez, que você não usará agora. Tornando o tempo de carregamento do aplicativo mais rápido que o normal.

Abhinaya Pandey
fonte
0

O Hiberante suporta o recurso de inicialização lenta para entidades e coleções. O mecanismo de hibernação carrega apenas os objetos que estamos consultando, mas não outras entidades ou coleções.

lazy = "false" por padrão, o carregamento da menção de inicialização para o filho único é preguiçoso. no caso de true que o pai esteja carregando, não há suporte para filho

abburi
fonte
0

A configuração preguiçosa decide se os objetos filhos devem ser carregados durante o carregamento do Objeto Pai. Você precisa fazer esta configuração no respectivo arquivo de mapeamento de hibernação da classe pai. Lazy = true (significa não carregar filhos) Por padrão, o carregamento lento dos objetos filhos é verdadeiro .

Manikandan Adhimoolam
fonte
0

Surpreendentemente, nenhuma das respostas fala sobre como isso é alcançado pelo hibernar atrás das telas.

O carregamento lento é um padrão de design que é efetivamente usado no hibernate por motivos de desempenho, que envolve as seguintes técnicas.


1. Instrumentação por código de bytes :

Aprimora a definição da classe base com ganchos de hibernação para interceptar todas as chamadas para esse objeto de entidade.

Feito no tempo de compilação ou no tempo de carregamento

1.1 Tempo de compilação

  • Operação pós-compilação

  • Principalmente por plugins maven / ant

1.2 Tempo de execução

  • Se não for feita nenhuma instrumentação em tempo de compilação, ela será criada em tempo de execução. Usando bibliotecas como javassist

2. Proxies

O objeto de entidade que o Hibernate retorna é proxy do tipo real.

Veja também: Javassist. Qual é a ideia principal e onde o uso real?

Sankarganesh Eswaran
fonte