EntityManager.merge()
pode inserir novos objetos e atualizar os existentes.
Por que alguém iria querer usar persist()
(que só pode criar novos objetos)?
jpa
merge
entitymanager
persist
java-persistence-api
Aaron Digulla
fonte
fonte
Respostas:
De qualquer forma, você adicionará uma entidade a um PersistenceContext, a diferença está no que você faz com a entidade posteriormente.
Persist pega uma instância de entidade, adiciona-a ao contexto e torna essa instância gerenciada (ou seja, futuras atualizações na entidade serão rastreadas).
A mesclagem retorna a instância gerenciada à qual o estado foi mesclado. Ele retorna algo que existe no PersistenceContext ou cria uma nova instância da sua entidade. De qualquer forma, ele copiará o estado da entidade fornecida e retornará a cópia gerenciada. A instância que você enviar não será gerenciada (quaisquer alterações que você fizer não farão parte da transação - a menos que você ligue para mesclar novamente). Você pode usar a instância retornada (gerenciada).
Talvez um exemplo de código ajude.
Os cenários 1 e 3 são aproximadamente equivalentes, mas há algumas situações em que você deseja usar o cenário 2.
fonte
merge
a cópia completa de um objeto antes de gerenciá-lo tenha um impacto no desempenho?@GeneratedId
posso obtê-lo no cenário 2?Persistir e mesclar são para dois propósitos diferentes (eles não são alternativas).
(editado para expandir informações sobre diferenças)
persistir:
mesclar:
eficiência persist ():
semântica persist ():
Exemplo:
Dessa maneira, existe apenas 1 objeto anexado para qualquer registro no gerenciador de entidades.
mesclar () para uma entidade com um ID é algo como:
Embora se conectado ao MySQL merge () possa ser tão eficiente quanto persist () usando uma chamada para INSERT com a opção ON DUPLICATE KEY UPDATE, o JPA é uma programação de nível muito alto e você não pode supor que esse seja o caso em todos os lugares.
fonte
em.persist(x)
comx = em.merge(x)
?merge()
também pode jogar um #EntityExistsException
RuntimeException
, mas não é mencionado no Javadoc.Se você estiver usando o gerador designado, usar mesclagem em vez de persistir pode causar uma instrução SQL redundante , afetando o desempenho.
Além disso, chamar a mesclagem para entidades gerenciadas também é um erro, pois as entidades gerenciadas são gerenciadas automaticamente pelo Hibernate e seu estado é sincronizado com o registro do banco de dados pelo mecanismo de verificação suja ao liberar o Contexto de Persistência .
Para entender como tudo isso funciona, primeiro você deve saber que o Hibernate muda a mentalidade do desenvolvedor de instruções SQL para transições de estado de entidade .
Depois que uma entidade for gerenciada ativamente pelo Hibernate, todas as alterações serão propagadas automaticamente para o banco de dados.
O Hibernate monitora as entidades atualmente conectadas. Mas, para que uma entidade seja gerenciada, ela deve estar no estado correto da entidade.
Para entender melhor as transições de estado da JPA, é possível visualizar o seguinte diagrama:
Ou se você usa a API específica do Hibernate:
Conforme ilustrado pelos diagramas acima, uma entidade pode estar em um dos quatro estados a seguir:
Novo (transitório)
Um objeto recém-criado que nunca foi associado a um Hibernate
Session
(akaPersistence Context
) e não está mapeado para nenhuma linha da tabela de banco de dados é considerado no estado Novo (Transitório).Para se tornar persistente, precisamos chamar explicitamente o
EntityManager#persist
método ou fazer uso do mecanismo de persistência transitiva.Persistente (gerenciado)
Uma entidade persistente foi associada a uma linha da tabela de banco de dados e está sendo gerenciada pelo Contexto de Persistência atualmente em execução. Qualquer alteração feita em uma entidade será detectada e propagada no banco de dados (durante o tempo de liberação da sessão). Com o Hibernate, não precisamos mais executar instruções INSERT / UPDATE / DELETE. O Hibernate emprega um estilo de trabalho de write-behind transacional e as alterações são sincronizadas no último momento responsável, durante o
Session
tempo de liberação atual .Independente
Depois que o contexto de persistência em execução no momento é fechado, todas as entidades gerenciadas anteriormente ficam desanexadas. As alterações sucessivas não serão mais rastreadas e nenhuma sincronização automática de banco de dados ocorrerá.
Para associar uma entidade desanexada a uma sessão de hibernação ativa, você pode escolher uma das seguintes opções:
Recolocação
O Hibernate (mas não o JPA 2.1) oferece suporte à recolocação através do método de atualização Session #. Uma sessão do Hibernate pode associar apenas um objeto de entidade a uma determinada linha do banco de dados. Isso ocorre porque o contexto de persistência atua como um cache na memória (cache de primeiro nível) e apenas um valor (entidade) é associado a uma determinada chave (tipo de entidade e identificador de banco de dados). Uma entidade pode ser reconectada apenas se não houver outro objeto da JVM (correspondendo à mesma linha do banco de dados) já associado à sessão atual do Hibernate.
Mesclando
A mesclagem copiará o estado da entidade desanexada (origem) para uma instância da entidade gerenciada (destino). Se a entidade mesclada não tiver equivalente na Sessão atual, uma será buscada no banco de dados. A instância do objeto desanexado continuará desanexada mesmo após a operação de mesclagem.
Removido
Embora o JPA exija que apenas as entidades gerenciadas possam ser removidas, o Hibernate também pode excluir entidades desanexadas (mas apenas por meio de uma chamada de método de exclusão da Sessão #). Uma entidade removida está agendada apenas para exclusão e a instrução DELETE real do banco de dados será executada durante o tempo de liberação da Sessão.
fonte
Percebi que, quando usei
em.merge
, recebi umaSELECT
declaração para cada umINSERT
, mesmo quando não havia um campo que o JPA estava gerando para mim - o campo da chave primária era um UUID que eu mesmo defini. Eu mudei paraem.persist(myEntityObject)
e recebi apenasINSERT
declarações então.fonte
merge()
. Eu tinha o banco de dados PostgreSQL com visão complicada : a visão agregava dados de várias tabelas (as tabelas tinham estrutura idêntica, mas com nomes diferentes). Então, o JPA tentou fazermerge()
, mas, na verdade, o JPA fez primeiroSELECT
(o banco de dados devido às configurações de exibição poderia retornar vários registros com a mesma chave primária de tabelas diferentes!), Depois o JPA (o Hibernate foi uma implementação) falhou: há vários registros com a mesma chave (org.hibernate.HibernateException: More than one row with the given identifier was found
) No meu casopersist()
me ajudou.A especificação JPA diz o seguinte sobre
persist()
.Portanto, o uso
persist()
seria adequado quando o objeto não deveria ser um objeto desanexado. Você pode preferir que o código lance o códigoPersistenceException
para que ele falhe rapidamente.Embora a especificação não seja clara ,
persist()
pode definir o@GeneratedValue
@Id
para um objeto.merge()
no entanto, deve ter um objeto com o@Id
já gerado.fonte
merge()
no entanto, deve ter um objeto com o@Id
já gerado . ". Sempre que o EntityManager não encontra um valor para o campo do ID do objeto, ele é persistido (inserido) no banco de dados.Mais alguns detalhes sobre a mesclagem que ajudarão você a usar a mesclagem persistir:
Todas as informações acima foram obtidas do "Pro JPA 2 Mastering the Java ™ Persistence API" por Mike Keith e Merrick Schnicariol. Capítulo 6. Desanexação e Mesclagem de Seção. Este livro é na verdade um segundo livro dedicado à JPA pelos autores. Este novo livro tem muitas informações novas e mais antigas. Eu realmente recomendo ler este livro para aqueles que se envolverão seriamente com a JPA. Sinto muito por postar anonimamente minha primeira resposta.
fonte
Existem mais algumas diferenças entre
merge
epersist
(vou enumerar novamente as que já foram postadas aqui):D1
merge
não torna a entidade transmitida gerenciada, mas retorna outra instância que é gerenciada.persist
por outro lado, fará com que a entidade transmitida seja gerenciada:D2 Se você remover uma entidade e decidir persistir com a entidade de volta, poderá fazê-lo apenas com persist (), porque
merge
lançará umIllegalArgumentException
.D3 Se você decidiu cuidar manualmente de seus IDs (por exemplo, usando UUIDs), uma
merge
operação acionaráSELECT
consultas subseqüentes para procurar entidades existentes com esse ID, emborapersist
possam não ser necessárias.D4 Há casos em que você simplesmente não confia no código que o chama e, para garantir que nenhum dado seja atualizado, mas inserido, você deve usá-lo
persist
.fonte
Eu estava recebendo exceções de LazyLoading na minha entidade porque estava tentando acessar uma coleção carregada de Lazy que estava em sessão.
O que eu faria era em uma solicitação separada, recuperava a entidade da sessão e tentava acessar uma coleção na minha página jsp, o que era problemático.
Para aliviar isso, atualizei a mesma entidade no meu controlador e a passei para o meu jsp, embora eu imagine que, quando eu salvei novamente na sessão, ele também estará acessível
SessionScope
e não lançará umaLazyLoadingException
, uma modificação do exemplo 2:O seguinte funcionou para mim:
fonte
Eu achei esta explicação dos documentos do Hibernate esclarecedora, porque eles contêm um caso de uso:
De: http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/objectstate.html
fonte
Analisando as respostas, faltam alguns detalhes sobre a geração em cascata e identificação. Ver pergunta
Além disso, vale ressaltar que você pode ter
Cascade
anotações separadas para mesclar e persistir:Cascade.MERGE
eCascade.PERSIST
que serão tratadas de acordo com o método usado.A especificação é sua amiga;)
fonte
Entidades persistentes
Em contraste com o método de mesclagem, o método persist é bastante direto e intuitivo. O cenário mais comum do uso do método persist pode ser resumido da seguinte forma:
"Uma instância recém-criada da classe de entidade é passada para o método persistente. Depois que esse método retorna, a entidade é gerenciada e planejada para inserção no banco de dados. Isso pode acontecer antes ou depois da confirmação da transação ou quando o método de liberação é chamado. Se a entidade referenciar outra entidade por meio de um relacionamento marcado com a estratégia em cascata PERSIST, esse procedimento também será aplicado a ela. "
A especificação entra mais em detalhes, no entanto, lembrá-los não é crucial, pois esses detalhes abrangem apenas situações mais ou menos exóticas.
Entidades de fusão
Em comparação com a persistência, a descrição do comportamento da mesclagem não é tão simples. Não há cenário principal, como no caso de persistir, e um programador deve lembrar de todos os cenários para escrever um código correto. Parece-me que os designers da JPA queriam ter algum método cuja principal preocupação fosse lidar com entidades desanexadas (como o oposto do método persistente que lida principalmente com entidades recém-criadas.) A principal tarefa do método de mesclagem é transferir o estado de um entidade não gerenciada (passada como argumento) para sua contraparte gerenciada no contexto de persistência. Essa tarefa, no entanto, divide-se ainda mais em vários cenários que pioram a inteligibilidade do comportamento geral do método.
Em vez de repetir parágrafos da especificação JPA, preparei um diagrama de fluxo que descreve esquematicamente o comportamento do método de mesclagem:
Então, quando devo usar persistir e quando mesclar?
persistir
fundir
fonte
Cenário X:
Tabela: Spitter (Um), Tabela: Spittles (Muitos) (Spittles é o proprietário do relacionamento com um FK: spitter_id)
Esse cenário resulta em economia: O Spitter e os dois Spittles como se pertencessem ao Mesmo Spitter.
Cenário Y:
Isso salvará o Spitter, salvará os 2 Spittles Mas eles não farão referência ao mesmo Spitter!
fonte
Outra observação:
merge()
só se preocupará com um ID gerado automaticamente (testadoIDENTITY
eSEQUENCE
) quando um registro com esse ID já existir em sua tabela. Nesse casomerge()
, tentará atualizar o registro. Se, no entanto, um ID estiver ausente ou não corresponder a nenhum registro existente,merge()
o ignorará completamente e solicitará ao banco de dados que aloque um novo. Às vezes, isso é fonte de muitos bugs. Não usemerge()
para forçar um ID para um novo registro.persist()
por outro lado, nunca permitirá que você passe um ID para ele. Falhará imediatamente. No meu caso, é:O hibernate-jpa javadoc tem uma dica:
fonte
persist()
não reclamará que possui um ID, apenas reclama quando algo com o mesmo ID já estiver no banco de dados.Você pode ter vindo aqui para obter conselhos sobre quando usar persistir e quando usar mesclagem . Eu acho que depende da situação: qual a probabilidade de você precisar criar um novo registro e qual a dificuldade de recuperar dados persistentes.
Vamos supor que você possa usar uma chave / identificador natural.
Os dados precisam persistir, mas de vez em quando existe um registro e é necessária uma atualização. Nesse caso, você pode tentar persistir e, se ele gerar uma EntityExistsException, procure e combine os dados:
tente {entityManager.persist (entity)}
catch (exceção EntityExistsException) {/ * recuperar e mesclar * /}
Os dados persistentes precisam ser atualizados, mas de vez em quando ainda não há registro para os dados. Nesse caso, você procura e persiste se a entidade estiver ausente:
Entidade = entityManager.find (chave);
if (entity == null) {entityManager.persist (entity); }
else {/ * mesclar * /}
Se você não tiver chave / identificador natural, será mais difícil descobrir se a entidade existe ou não, ou como procurá-la.
As mesclagens também podem ser tratadas de duas maneiras:
fonte
persist (entidade) deve ser usado com entidades totalmente novas, para adicioná-las ao DB (se a entidade já existir no DB, haverá lançamento de EntityExistsException).
a mesclagem (entidade) deve ser usada para colocar a entidade de volta ao contexto de persistência se a entidade foi desanexada e foi alterada.
Provavelmente persistir está gerando INSERT sql e mesclar UPDATE sql (mas não tenho certeza).
fonte