Hibernate: Diferença entre session.get e session.load

88

Pela API, pude ver que tem algo a ver com proxy. Mas não consegui encontrar muitas informações sobre proxy e não entendi a diferença entre chamar session.gete session.load. Alguém poderia me explicar ou direcionar para uma página de referência?

Obrigado!!

tomate
fonte

Respostas:

117

No fórum do Hibernate :

Isso é do livro Hibernate em ação. Bom ler isso ..


Recuperando objetos por identificador O seguinte trecho de código do Hibernate recupera um objeto Usuário do banco de dados:

User user = (User) session.get(User.class, userID);

O método get () é especial porque o identificador identifica exclusivamente uma única instância de uma classe. Portanto, é comum que os aplicativos usem o identificador como um identificador conveniente para um objeto persistente. A recuperação por identificador pode usar o cache ao recuperar um objeto, evitando uma ocorrência no banco de dados se o objeto já estiver armazenado em cache. O Hibernate também fornece um método load ():

User user = (User) session.load(User.class, userID);

O método load () é mais antigo; get () foi adicionado à API do Hibernate devido à solicitação do usuário. A diferença é trivial:

Se load () não puder encontrar o objeto no cache ou banco de dados, uma exceção é lançada. O método load () nunca retorna nulo. O método get () retorna null se o objeto não puder ser encontrado.

O método load () pode retornar um proxy em vez de uma instância persistente real. Um proxy é um espaço reservado que dispara o carregamento do objeto real quando ele é acessado pela primeira vez; Por outro lado, get () nunca retorna um proxy. Escolher entre get () e load () é fácil: se você tiver certeza de que o objeto persistente existe e que a inexistência seria considerada excepcional, load () é uma boa opção. Se você não tiver certeza de que existe uma instância persistente com o identificador fornecido, use get () e teste o valor de retorno para ver se é nulo. Usar load () tem outra implicação: o aplicativo pode recuperar uma referência válida (um proxy) para uma instância persistente sem acessar o banco de dados para recuperar seu estado persistente. Portanto, load () pode não lançar uma exceção quando não encontrar o objeto persistente no cache ou banco de dados; a exceção seria lançada posteriormente, quando o proxy fosse acessado. Claro, recuperar um objeto por identificador não é tão flexível quanto usar consultas arbitrárias.

duffymo
fonte
1
Estou depurando um problema agora em que session.Get <T> () está retornando um proxy!
Kent Boogaart
7
Muito obrigado! A parte do dinheiro para mim foi: "Se load () não puder encontrar o objeto no cache ou banco de dados, uma exceção é lançada. O método get () retorna null se o objeto não pode ser encontrado."
Chris
15
O JavaDoc para Session.get diz: Retorne a instância persistente da classe de entidade fornecida com o identificador fornecido, ou null se não houver tal instância persistente. (Se a instância, ou um proxy para a instância, já estiver associado à sessão, retorne essa instância ou proxy.) Portanto, a seção do livro que diz: "Por outro lado, get () nunca retorna um proxy." não está correto.
Vicky
se você estiver usando uma estratégia de gerenciamento de transações com seus daos, pode preferir get (). caso contrário, o chamador também precisará estar executando no contexto de uma sessão de hibernação aberta no caso de load () retornar um proxy. por exemplo, se você estiver fazendo MVC, seu controlador pode executar dao.load () e então lançar uma exceção ao tentar acessar o objeto proxy posteriormente se não houver uma sessão válida. fazer dao.get () retornará o objeto real para o controlador, independentemente da sessão (assumindo que exista)
dev
O problema descrito por @Vicky pode causar dores de cabeça, e não vejo nenhuma vantagem nisso. Em alguns casos, também preciso do identificador para outras consultas parametrizadas. Mas como um proxy do objeto já está na sessão, o getter do identificador retorna nulo. Por que eles recuperam o proxy em vez da instância real se esse proxy está na sessão?
djmj
15

Bem, pelo menos no nhibernate, session.Get (id) carregará o objeto do banco de dados, enquanto session.Load (id) apenas cria um objeto proxy para ele sem deixar seu servidor. Funciona exatamente como qualquer outra propriedade de carregamento lento em seus POCOs (ou POJOs :). Você pode então usar este proxy como uma referência ao próprio objeto para criar relacionamentos, etc.

Pense nisso como ter um objeto que mantém apenas o Id e que carregará o resto se você precisar dele. Se você está apenas distribuindo-o para criar relacionamentos (como FKs), o id é tudo o que você precisa.

Jorge Alves
fonte
então você quer dizer que load (id) irá primeiro acertar o banco de dados para verificar se é uma id válida ou não e então retornará o objeto proxy e quando as propriedades deste objeto forem acessadas ele irá acessar o banco de dados novamente? não é um cenário improvável? duas consultas para carregar um único objeto?
faisalbhagat de
Não, load (id) não validará o id de forma alguma, portanto, nenhuma viagem de ida e volta para o banco de dados. Use-o apenas quando tiver certeza de que é válido.
Jorge Alves
9

session.load () sempre retornará um “proxy” (termo do Hibernate) sem atingir o banco de dados. No Hibernate, proxy é um objeto com um determinado valor de identificador, suas propriedades ainda não foram inicializadas, ele apenas se parece com um objeto falso temporário. Se nenhuma linha for encontrada, ele lançará uma ObjectNotFoundException.

session.get () sempre atinge o banco de dados e retorna o objeto real, um objeto que representa a linha do banco de dados, não proxy. Se nenhuma linha for encontrada, ele retorna nulo.

O desempenho com esses métodos também torna as diferenças. Entre dois...

Vishal Sharma
fonte
3

Mais um ponto extra ::

O método get da classe Hibernate Session retorna null se o objeto não for encontrado no cache, bem como no banco de dados. enquanto o método load () lança ObjectNotFoundException se o objeto não for encontrado no cache, bem como no banco de dados, mas nunca retorna nulo.

madhu_karnati
fonte
2

Uma consequência indireta do uso de "load" em vez de "get" é que o bloqueio otimista usando um atributo de versão pode não funcionar como você esperava. Se um carregamento simplesmente criar um proxy e não ler do banco de dados, a propriedade de versão não será carregada. A versão só será carregada quando / se posteriormente você fizer referência a uma propriedade no objeto, acionando um select. Nesse ínterim, outra sessão pode atualizar o objeto, e sua sessão não terá a versão original necessária para fazer a verificação de bloqueio otimista - portanto, a atualização da sua sessão sobrescreverá a atualização da outra sessão sem nenhum aviso.

Aqui está uma tentativa de esboçar esse cenário com duas sessões trabalhando com um objeto com o mesmo identificador. A versão inicial do objeto no DB é 10.

Session 1                  Session 2
---------                  ---------
Load object
Wait a while..   
                           Load object
                           Modify object property
                           [triggers db 'select' -
                            version read as 10]
                           Commit
                           [triggers db update,
                            version modified to 11]
Modify object property
  [triggers db 'select' -
  version read as 11]
Commit
  [triggers db update,
  version modified to 12]

Na verdade, queremos que o commit da sessão 1 falhe com uma exceção de bloqueio otimista, mas terá sucesso aqui.

Usar "get" em vez de "load" contorna o problema, porque get imediatamente emitirá um select e os números de versão serão carregados nos momentos corretos para a verificação de bloqueio otimista.

SteveT
fonte
0

Além disso, devemos ter cuidado ao usar load, pois isso lançará uma exceção se o objeto não estiver presente. Temos que usá-lo apenas quando tivermos certeza de que o objeto existe.

Sanjay
fonte
0

Uma excelente explicação pode ser encontrada em http://www.mkyong.com/hibernate/different-between-session-get-and-session-load
session.load ():
Ele sempre retornará um “proxy” (termo do Hibernate) sem acertando o banco de dados.
No Hibernate, proxy é um objeto com um determinado valor de identificador, suas propriedades ainda não foram inicializadas, ele apenas se parece com um objeto falso temporário.
Ele sempre retornará um objeto proxy com o valor de identidade fornecido, mesmo que o valor de identidade não exista no banco de dados. No entanto, quando você tenta inicializar um proxy recuperando suas propriedades do banco de dados, ele atingirá o banco de dados com a instrução select. Se nenhuma linha for encontrada, um ObjectNotFoundException será lançado.
session.get ():
Ele sempre atinge o banco de dados (se não for encontrado no cache) e retorna o objeto real, um objeto que representa a linha do banco de dados, não o proxy.
Se nenhuma linha for encontrada, ele retorna nulo.

jack preto
fonte
0

load () não pode encontrar o objeto do cache ou banco de dados, uma exceção é lançada e o método load () nunca retorna nulo.

O método get () retorna null se o objeto não pode ser encontrado. O método load () pode retornar um proxy em vez de uma instância persistente real get () nunca retorna um proxy.

Yasser Shaikh
fonte