EntityManager.merge() pode inserir novos objetos e atualizar os existentes.
Por que alguém iria querer usar persist()(que só pode criar novos objetos)?
— Bozho 12/12/12
Se você gosta de diagramas. Consulte isto: spitballer.blogspot.in/2010/04/…
— RBz 26/06
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.
@dma_k: Parece que você está usando o Hibernate. Estou menos familiarizado com o Hibernate do que com o JPA - mas no JPA, se você chamar EntityManager.persist () e transmitir uma entidade desanexada, você irá: a) obter uma EntityExistsException imediatamente ou b) obter outra PersistenceException no momento da liberação / confirmação. Talvez eu tenha entendido mal a pergunta aqui?
Essa resposta poderá ser melhorada se também cobrir os casos em que a entidade que está sendo mesclada / persistente já existe no contexto persistente (ou pelo menos deixou mais claro que só descreve o comportamento quando a entidade persistida / mesclada ainda não existe)
Um método é mais eficiente? Talvez mergea cópia completa de um objeto antes de gerenciá-lo tenha um impacto no desempenho?
E os ids? Se eu tiver um, @GeneratedIdposso obtê-lo no cenário 2?
— rascio 25/03
Mike: "Mesclar cria uma nova instância ...": isso nem sempre é verdade. Se o EntityManager encontrar uma entidade já gerenciada em seu contexto, ele retornará esta instância (depois de atualizar os campos). Por favor edite sua resposta, então votarei nela.
Persistir e mesclar são para dois propósitos diferentes (eles não são alternativas).
(editado para expandir informações sobre diferenças)
Inserir um novo registro no banco de dados
Anexe o objeto ao gerente da entidade.
Encontre um objeto anexado com o mesmo ID e atualize-o.
Se existir, atualize e retorne o objeto já anexado.
Se não existir, insira o novo registro no banco de dados.
eficiência persist ():
Poderia ser mais eficiente inserir um novo registro em um banco de dados do que merge ().
Não duplica o objeto original.
semântica persist ():
Ele garante que você esteja inserindo e não atualizando por engano.
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.
Você pode citar um caso em que não é válido para substituir em.persist(x)com x = em.merge(x)?
persist () pode lançar uma EntityExistsException. Se você deseja ter certeza de que seu código está inserindo e não uma atualização dos dados, você deve usar persistir.
merge()também pode jogar um #EntityExistsException
@None Poderia porque é um 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(aka Persistence 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#persistmé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 Sessiontempo de liberação atual .
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:
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.
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.
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.
você pode dar uma olhada em stackoverflow.com/questions/46214322/… ?
@gstackoverflow A resposta que você obteve é ​​a correta. Para mais detalhes, consulte este artigo ou meu livro, Persistência Java de alto desempenho .
— Vlad Mihalcea 14/09
Portanto, não há possibilidade de alterar a ordem da operação para orphanremoval = true?
Seu artigo sobre ordem de operação no caso usual. Minha pergunta específica para orphanRemoval
O fato é que é impossível explicar a hibernação com um diagrama como esse. Por que você não pode liberar a sessão após desanexar? O que acontece quando você tenta salvar uma entidade já persistida? Por que esse comportamento de liberação é diferente quando se trata de salvar e persistir? Existem 1000 perguntas desse tipo, para as quais ninguém tem uma lógica clara.
— GingerBeer
Percebi que, quando usei em.merge, recebi uma SELECTdeclaração para cada um INSERT, 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 para em.persist(myEntityObject)e recebi apenas INSERTdeclarações então.
Faz sentido, pois você atribui os IDs e o contêiner JPA não faz ideia de onde você tirou isso. Há uma (pequena) chance de que o objeto já exista no banco de dados, por exemplo, em um cenário em que vários aplicativos gravam no mesmo banco de dados.
Eu já enfrentei um problema semelhante 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 fazer merge(), mas, na verdade, o JPA fez primeiro SELECT(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 caso persist()me ajudou.
A especificação JPA diz o seguinte sobre persist().
Se X for um objeto desanexado, ele EntityExistsExceptionpoderá ser lançado quando a operação persistir for invocada ou a EntityExistsExceptionoutra PersistenceExceptionpoderá ser lançada no momento da liberação ou confirmação.
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ódigo PersistenceExceptionpara que ele falhe rapidamente.
Embora a especificação não seja clara , persist()pode definir o @GeneratedValue @Idpara um objeto. merge()no entanto, deve ter um objeto com o @Idjá gerado.
+1 para " 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.
Eu não entendi isso primeiro, porque eu não estava claro sobre os estados. Espero que isso ajude alguém como fez para mim. docs.jboss.org/hibernate/core/3.6/reference/en-US/html/…
@GeneratedValue não tem incidência diferente para merge () e persistir ()
— SandeepGodara
Mais alguns detalhes sobre a mesclagem que ajudarão você a usar a mesclagem persistir:
Retornar uma instância gerenciada que não seja a entidade original é uma parte crítica do processo de mesclagem. Se uma instância de entidade com o mesmo identificador já existir no contexto de persistência, o provedor substituirá seu estado pelo estado da entidade que está sendo mesclada, mas a versão gerenciada que já existia deverá ser retornada ao cliente para que possa ser usava. Se o provedor não atualizar a instância Employee no contexto de persistência, quaisquer referências a essa instância se tornarão inconsistentes com o novo estado que está sendo mesclado.
Quando merge () é chamado em uma nova entidade, ele se comporta de maneira semelhante à operação persist (). Ele adiciona a entidade ao contexto de persistência, mas, em vez de adicionar a instância da entidade original, cria uma nova cópia e gerencia essa instância. A cópia criada pela operação merge () é mantida como se o método persist () tivesse sido chamado nela.
Na presença de relacionamentos, a operação merge () tentará atualizar a entidade gerenciada para apontar para versões gerenciadas das entidades referenciadas pela entidade desanexada. Se a entidade tiver um relacionamento com um objeto que não tem identidade persistente, o resultado da operação de mesclagem será indefinido. Alguns provedores podem permitir que a cópia gerenciada aponte para o objeto não persistente, enquanto outros podem lançar uma exceção imediatamente. A operação merge () pode ser opcionalmente em cascata nesses casos para impedir que uma exceção ocorra. Abordaremos a cascata da operação merge () posteriormente nesta seção. Se uma entidade que está sendo mesclada aponta para uma entidade removida, uma exceção IllegalArgumentException será lançada.
Os relacionamentos de carregamento lento são um caso especial na operação de mesclagem. Se um relacionamento de carregamento lento não foi acionado em uma entidade antes de ser desanexado, esse relacionamento será ignorado quando a entidade for mesclada. Se o relacionamento foi acionado enquanto gerenciado e, em seguida, definido como nulo enquanto a entidade foi desanexada, a versão gerenciada da entidade também terá o relacionamento limpo durante a mesclagem. "
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.
— Khurshed Salimov
Existem mais algumas diferenças entre mergee persist(vou enumerar novamente as que já foram postadas aqui):
D1 mergenão torna a entidade transmitida gerenciada, mas retorna outra instância que é gerenciada. persistpor 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 mergelançará um IllegalArgumentException.
D3 Se você decidiu cuidar manualmente de seus IDs (por exemplo, usando UUIDs), uma merge operação acionará SELECTconsultas subseqüentes para procurar entidades existentes com esse ID, embora persistpossam 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.
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 SessionScopee não lançará uma LazyLoadingException, uma modificação do exemplo 2:
Eu achei esta explicação dos documentos do Hibernate esclarecedora, porque eles contêm um caso de uso:
O uso e a semântica de merge () parecem confusos para novos usuários. Em primeiro lugar, desde que você não esteja tentando usar o estado do objeto carregado em um gerenciador de entidades em outro novo gerenciador de entidades, não será necessário usar merge () . Alguns aplicativos inteiros nunca usarão esse método.
Normalmente, merge () é usado no seguinte cenário:
O aplicativo carrega um objeto no primeiro gerenciador de entidades
o objeto é passado para a camada de apresentação
algumas modificações são feitas no objeto
o objeto é passado de volta para a camada de lógica de negócios
o aplicativo persiste essas modificações chamando merge () em um segundo gerenciador de entidades
Aqui está a semântica exata de merge ():
se houver uma instância gerenciada com o mesmo identificador atualmente associado ao contexto de persistência, copie o estado do objeto fornecido na instância gerenciada
se não houver uma instância gerenciada atualmente associada ao contexto de persistência, tente carregá-la no banco de dados ou crie uma nova instância gerenciada
a instância gerenciada é retornada
a instância fornecida não se associa ao contexto de persistência, permanece desanexada e geralmente é descartada
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 Cascadeanotações separadas para mesclar e persistir: Cascade.MERGEe Cascade.PERSISTque serão tratadas de acordo com o método usado.
A especificação é sua amiga;)
— Ioannis Deligiannis
O JPA é indiscutivelmente uma grande simplificação no domínio de aplicativos corporativos criados na plataforma Java. Como desenvolvedor que teve que lidar com as complexidades dos beans de entidade antigos no J2EE, vejo a inclusão do JPA entre as especificações do Java EE como um grande salto em frente. No entanto, ao me aprofundar nos detalhes da JPA, encontro coisas que não são tão fáceis. Neste artigo, trato da comparação dos métodos de mesclagem e persistência do EntityManager, cujo comportamento sobreposto pode causar confusão não apenas a um novato. Além disso, proponho uma generalização que vê ambos os métodos como casos especiais de um método mais geral combinados.
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?
Você deseja que o método sempre crie uma nova entidade e nunca atualize uma entidade. Caso contrário, o método lança uma exceção como consequência da violação de exclusividade da chave primária.
Processos em lote, manipulando entidades de maneira com estado (consulte Padrão de gateway).
Você deseja que o método insira ou atualize uma entidade no banco de dados.
Você deseja manipular entidades de maneira sem estado (objetos de transferência de dados nos serviços)
Você deseja inserir uma nova entidade que possa ter uma referência a outra entidade que pode, mas ainda não pode ser criada (o relacionamento deve ser marcado como MERGE). Por exemplo, inserir uma nova foto com uma referência a um álbum novo ou a um álbum preexistente.
— Amit Gujarathi
Qual é a diferença entre E é gerenciado e O PC contém uma versão gerenciada de E?
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!
— George Papatheodorou
O cuspidor é um objeto retirado do livro "Spring in Action" terceira edição de Graig Walls. Spitters são pessoas que dizem algo e seu Spittle é o que estão realmente dizendo. Portanto, um Spitter tem muitos spittles significa que ele tem uma lista de Strings.
Você poderia ter usado um exemplo que é um pouco mais legível sem ler Primavera em ação ...
— wonderb0lt
Você precisa realmente não faça saber o que é uma saliva ou um cuspidor desde no topo, está escrito que Spitter é uma tabela, spitter é outra tabela que possui .. isso e aquilo ...
merge()só se preocupará com um ID gerado automaticamente (testado IDENTITYe SEQUENCE) quando um registro com esse ID já existir em sua tabela. Nesse caso merge(), 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 use merge()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, é:
Causado por: org.hibernate.PersistentObjectException: entidade desanexada passada para persistir
O hibernate-jpa javadoc tem uma dica:
Lança : javax.persistence.EntityExistsException - se a entidade já existir. (Se a entidade já existir, a EntityExistsException poderá ser lançada quando a operação persistir for invocada ou a EntityExistsException ou outra PersistenceException poderá ser lançada no momento da liberação ou confirmação.)
Se você não estiver usando IDs gerados automaticamente, precisará atribuir um ID à sua nova entidade manualmente. 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);
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:
Se as alterações geralmente são pequenas, aplique-as à entidade gerenciada.
Se as alterações forem comuns, copie o ID da entidade persistente, bem como dados inalterados. Em seguida, chame EntityManager :: merge () para substituir o conteúdo antigo.
— Peter Willems
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).
Isto está incorreto. Se você chamar mesclagem (e) em um novo e, ele deverá persistir.
— Pedro Lamarão
@ PedroLamarão warren.chinalle.com/wp-content/uploads/2011/09/…
Na versão 2.1 da especificação JPA, seção 3.2.7.1, segundo marcador: "Se X é uma nova instância de entidade, uma nova instância de entidade gerenciada X 'é criada e o estado de X é copiado na nova instância de entidade gerenciada X'."