Proxy no método load () do Hibernate

Proxy no método load () do Hibernate

1. Visão geral

Neste tutorial, veremos o que é um proxy no contexto do métodoload() do Hibernate.

Para leitores novos no Hibernate, considere se familiarizar combasics primeiro.

2. Uma breve introdução aos proxies e métodoload()

By definition, a proxy is “a function authorized to act as the deputy or substitute for another”.

Isso se aplica ao Hibernate quando chamamosSession.load() para criar o que é chamado deuninitialized proxy para nossa classe de entidade desejada.

Simplificando, o Hibernate subclasses de nossa classe de entidade, usando a bibliotecaCGLib. Além do método@Id, a implementação do proxy delega todos os outros métodos de propriedade para a sessão do Hibernate para preencher a instância, algo como:

public class HibernateProxy extends MyEntity {
    private MyEntity target;

    public String getFirstName() {
        if (target == null) {
            target = readFromDatabase();
        }
        return target.getFirstName();
    }
}

Essa subclasse será aquela a ser retornada em vez de consultar o banco de dados diretamente.

Depois que um dos métodos de entidade é chamado, a entidade é carregada e, nesse ponto, torna-se uminitialized proxy.

3. Proxies e Lazyloading

3.1. Uma única entidade

Vamos pensar sobreEmployee as uma entidade. Para começar, vamos supor que não tem relação com nenhuma outra tabela.

Se usarmosSession.load() para instanciar umEmployee:

Employee albert = session.load(Employee.class, new Long(1));

Então o Hibernate irá criar um proxy não inicializado deEmployee. It will contain the ID that we gave it but otherwise will have no other values because we haven’t hit the database yet.

No entanto, uma vez que chamamos um método emalbert:

String firstName = albert.getFirstName();

Então o Hibernate irá consultar a tabela do banco de dadosemployee para uma entidade com uma chave primária de 1, populandoalbert com suas propriedades da linha correspondente.

Se falhar em encontrar uma linha, o Hibernate lança umObjectNotFoundException.

3.2. Relacionamentos Um-para-Muitos

Agora, vamos criar umCompany entity também, onde umCompany  tem muitosEmployees:

public class Company {
    private String name;
    private Set employees;
}

Se desta vez usarmosSession.load() filho, a empresa:

Company bizco = session.load(Company.class, new Long(1));
String name = bizco.getName();

Em seguida, as propriedades da empresa são preenchidas como antes, exceto que o conjunto de funcionários é um pouco diferente.

Veja, nós apenas consultamos a linha da empresa, mas o proxy deixará o funcionário sozinho até que chamemosgetEmployees dependendo da estratégia de busca.

3.3. Relacionamentos muitos para um

O caso é semelhante na direção oposta:

public class Employee {
    private String firstName;
    private Company workplace;
}

Se usarmosload() novamente:

Employee bob = session.load(Employee.class, new Long(2));
String firstName = bob.getFirstName();

bob will agora foi inicializado e, na verdade,workplace agora será definido como um proxy não inicializado, dependendo da estratégia de busca.

4. Carregamento lento

Agora,load() nem sempre nos fornece um proxy não inicializado. Na verdade, oSession java doc nos lembra (ênfase adicionada):

Este métodomight retorna uma instância com proxy que é inicializada sob demanda, quando um método não identificador é acessado.

Um exemplo simples de quando isso pode acontecer é com o tamanho do lote.

Digamos que estejamos usando@BatchSize em nossaEmployee entity:

@Entity
@BatchSize(size=5)
class Employee {
    // ...
}

E desta vez temos três funcionários:

Employee catherine = session.load(Employee.class, new Long(3));
Employee darrell = session.load(Employee.class, new Long(4));
Employee emma = session.load(Employee.class, new Long(5));

Se chamarmosgetFirstName oncatherine:

String cathy = catherine.getFirstName();

Então, na verdade, o Hibernate pode decidir carregar todos os três funcionários de uma vez, transformando todos os três em proxies inicializados.

E então, quando pedimos o primeiro nome dedarrell:

String darrell = darrell.getFirstName();

EntãoHibernate doesn’t hit the database at all.

5. Carregamento ansioso

5.1. Usandoget()

Também podemos ignorar os proxies completamente e pedir ao Hibernate para carregar a coisa real usandoSession.get():

Employee finnigan = session.get(Employee.class, new Long(6));

Isso chamará o banco de dados imediatamente, em vez de retornar um proxy.

E, na verdade, em vez deObjectNotFoundException, ele retornaránull sefinnigan  não existir.

5.2. Implicações de desempenho

Emboraget() seja conveniente,load() pode ser mais leve no banco de dados.

Por exemplo, digamos quegerald is vai trabalhar para uma nova empresa:

Employee gerald = session.get(Employee.class, new Long(7));
Company worldco = (Company) session.load(Company.class, new Long(2));
employee.setCompany(worldco);
session.save(employee);

Como sabemos que só vamos alterar o registroemployee nesta situação,, chamandoload() paraCompany  é sensato.

Se chamarmosget() emCompany, teríamos carregado todos os seus dados desnecessariamente do banco de dados.

6. Conclusão

Neste artigo, aprendemos brevemente como os proxiesHibernate funcionam e como isso afeta o métodoload com entidades e seus relacionamentos.

Além disso, demos uma olhada rápida em comoload() difere deget().

Como de costume, o código-fonte completo que acompanha o tutorial está disponívelover on GitHub.