Quali sono le differenze tra i diversi metodi di salvataggio in Hibernate?

Hibernate ha una manciata di metodi che, in un modo o nell’altro, prendono il tuo object e lo inseriscono nel database. Quali sono le differenze tra loro, quando usare quale e perché non c’è un solo metodo intelligente che sa quando usare cosa?

I metodi che ho identificato finora sono:

  • save()
  • update()
  • saveOrUpdate()
  • saveOrUpdateCopy()
  • merge()
  • persist()

Ecco la mia comprensione dei metodi. Principalmente questi sono basati sull’API anche se non li uso tutti in pratica.

saveOrUpdate Le chiamate vengono salvate o aggiornate a seconda di alcuni controlli. Ad esempio, se non esiste alcun identificatore, viene richiamato il salvataggio. Altrimenti viene chiamato l’aggiornamento.

salva Persiste un’ quadro. Assegnerà un identificatore se non esiste. Se lo si fa, è essenzialmente facendo un aggiornamento. Restituisce l’ID generato dell’ quadro.

aggiornamento Tenta di mantenere l’ quadro utilizzando un identificatore esistente. Se non esiste alcun identificatore, credo che venga lanciata un’eccezione.

saveOrUpdateCopy Questo è deprecato e non dovrebbe più essere utilizzato. Invece c’è …

unire Ora è qui che la mia conoscenza inizia a vacillare. La cosa importante qui è la differenza tra quadro transienti, distaccate e persistenti. Per maggiori informazioni sugli stati dell’object, dai un’occhiata qui . Con il salvataggio e l’aggiornamento, hai a che fare con oggetti persistenti. Sono collegati a una sessione in modo che Hibernate sappia cosa è cambiato. Ma quando hai un object transitorio, non c’è nessuna sessione coinvolta. In questi casi è necessario utilizzare l’unione per gli aggiornamenti e persistere per il salvataggio.

persist Come detto sopra, questo è usato su oggetti transitori. Non restituisce l’ID generato.

 ╔══════════════╦═══════════════════════════════╦════════════════════════════════╗ ║ METHOD ║ TRANSIENT ║ DETACHED ║ ╠══════════════╬═══════════════════════════════╬════════════════════════════════╣ ║ ║ sets id if doesn't ║ sets new id even if object ║ ║ save() ║ exist, persists to db, ║ already has it, persists ║ ║ ║ returns attached object ║ to DB, returns attached object ║ ╠══════════════╬═══════════════════════════════╬════════════════════════════════╣ ║ ║ sets id on object ║ throws ║ ║ persist() ║ persists object to DB ║ PersistenceException ║ ║ ║ ║ ║ ╠══════════════╬═══════════════════════════════╬════════════════════════════════╣ ║ ║ ║ ║ ║ update() ║ Exception ║ persists and reattaches ║ ║ ║ ║ ║ ╠══════════════╬═══════════════════════════════╬════════════════════════════════╣ ║ ║ copy the state of object in ║ copy the state of obj in ║ ║ merge() ║ DB, doesn't attach it, ║ DB, doesn't attach it, ║ ║ ║ returns attached object ║ returns attached object ║ ╠══════════════╬═══════════════════════════════╬════════════════════════════════╣ ║ ║ ║ ║ ║saveOrUpdate()║ as save() ║ as update() ║ ║ ║ ║ ║ ╚══════════════╩═══════════════════════════════╩════════════════════════════════╝ 
  • Vedi il Forum di Hibernate per una spiegazione delle sottili differenze tra persist e save. Sembra che la differenza sia il momento in cui l’istruzione INSERT viene eseguita alla fine. Poiché save restituisce l’identificatore, l’istruzione INSERT deve essere eseguita immediatamente indipendentemente dallo stato della transazione (che in genere è una cosa negativa). Persist non eseguirà alcuna istruzione al di fuori della transazione attualmente in esecuzione solo per assegnare l’identificatore. Salvare / Persistere entrambi i lavori su istanze transitori , vale a dire le istanze che non hanno ancora un identificatore assegnato e come tali non vengono salvati nel DB.

  • Aggiorna e Unisci funzionano sia su istanze distaccate , vale a dire le istanze che hanno una voce corrispondente nel DB ma che non sono attualmente associate a (o gestite da) una Sessione. La differenza tra loro è ciò che accade all’istanza che viene passata alla funzione. update tenta di ricolbind l’istanza, il che significa che non ci può essere un’altra istanza dell’ quadro persistente collegata alla Sessione in questo momento altrimenti viene generata un’eccezione. Unire , tuttavia, copia semplicemente tutti i valori su un’istanza persistente nella Session (che verrà caricata se non è attualmente caricata). L’object di input non è cambiato. Quindi l’ unione è più generale dell’aggiornamento , ma può utilizzare più risorse.

Questo link spiega in modo corretto:

http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/

Abbiamo tutti quei problemi che incontriamo abbastanza raramente che quando li vediamo di nuovo, sappiamo che abbiamo risolto questo problema, ma non ricordo come.

L’eccezione NonUniqueObject generata quando si utilizza Session.saveOrUpdate () in Hibernate è una delle mie. Aggiungerò nuove funzionalità a un’applicazione complessa. Tutti i miei test unitari funzionano bene. Quindi, testando l’interfaccia utente, provando a salvare un object, ho iniziato a ricevere un’eccezione con il messaggio “un object diverso con lo stesso valore identificatore era già associato alla sessione.” Ecco alcuni esempi di codice da Java Persistence con Hibernate.

  Session session = sessionFactory1.openSession(); Transaction tx = session.beginTransaction(); Item item = (Item) session.get(Item.class, new Long(1234)); tx.commit(); session.close(); // end of first session, item is detached item.getId(); // The database identity is "1234" item.setDescription("my new description"); Session session2 = sessionFactory.openSession(); Transaction tx2 = session2.beginTransaction(); Item item2 = (Item) session2.get(Item.class, new Long(1234)); session2.update(item); // Throws NonUniqueObjectException tx2.commit(); session2.close(); 

Per capire la causa di questa eccezione, è importante capire gli oggetti distaccati e cosa succede quando si chiama saveOrUpdate () (o semplicemente update ()) su un object staccato.

Quando chiudiamo una singola sessione di ibernazione, gli oggetti persistenti con cui stiamo lavorando sono staccati. Ciò significa che i dati sono ancora nella memoria dell’applicazione, ma Hibernate non è più responsabile del rilevamento delle modifiche agli oggetti.

Se poi modifichiamo il nostro object distaccato e vogliamo aggiornarlo, dobbiamo ricolbind l’object. Durante questo processo di ricollegamento, Hibernate controlla se ci sono altre copie dello stesso object. Se trova qualcosa, deve dirci che non sa più quale sia la copia “reale”. Forse sono state apportate altre modifiche a quelle altre copie che ci aspettiamo vengano salvate, ma Hibernate non ne sa nulla, perché non le gestiva in quel momento.

Anziché salvare dati potenzialmente errati, Hibernate ci parla del problema tramite NonUniqueObjectException.

Quindi cosa dobbiamo fare? In Hibernate 3, abbiamo unire () (in Hibernate 2, usare saveOrUpdateCopy ()). Questo metodo costringerà Hibernate a copiare qualsiasi modifica da altre istanze distaccate sull’istanza che si desidera salvare e quindi unirà tutte le modifiche in memoria prima del salvataggio.

  Session session = sessionFactory1.openSession(); Transaction tx = session.beginTransaction(); Item item = (Item) session.get(Item.class, new Long(1234)); tx.commit(); session.close(); // end of first session, item is detached item.getId(); // The database identity is "1234" item.setDescription("my new description"); Session session2 = sessionFactory.openSession(); Transaction tx2 = session2.beginTransaction(); Item item2 = (Item) session2.get(Item.class, new Long(1234)); Item item3 = session2.merge(item); // Success! tx2.commit(); session2.close(); 

È importante notare che l’unione restituisce un riferimento alla versione appena aggiornata dell’istanza. Non sta riattaccando l’object alla Sessione. Se esegui il test dell’eguaglianza di esempio (item == item3), troverai che in questo caso restituisce false. Probabilmente vorrai lavorare con item3 da questo punto in poi.

È anche importante notare che Java Persistence API (JPA) non ha un concetto di oggetti staccati e ricollegati e utilizza EntityManager.persist () ed EntityManager.merge ().

Ho trovato in generale che quando si utilizza Hibernate, saveOrUpdate () è in genere sufficiente per le mie esigenze. Di solito ho solo bisogno di unire quando ho oggetti che possono avere riferimenti a oggetti dello stesso tipo. Più di recente, la causa dell’eccezione era nel codice che convalidava che il riferimento non era ricorsivo. Stavo caricando lo stesso object nella mia sessione come parte della convalida, causando l’errore.

Dove hai incontrato questo problema? Unire lavoro per te o hai bisogno di un’altra soluzione? Preferisci sempre utilizzare l’unione o preferisci usarlo solo se necessario per casi specifici

In realtà la differenza tra i metodi hibernate save() e persist() dipende dalla class del generatore che stiamo usando.

Se viene assegnata la nostra class di generatore, non vi è alcuna differenza tra i metodi save() e persist( ). Poiché il generatore “assegnato” significa, come programmatore, è necessario fornire il valore della chiave primaria per il salvataggio nel database corretto. Spero che tu conosca questo concetto di generatore. In caso di class generatrice diversa da quella assegnata, supponiamo che il nostro nome di class generatore sia Incremento hibernate it self assegnerà il valore id della chiave primaria nel database a destra [diverso dal generatore assegnato, hibernate usato solo per fare attenzione a ricordare il valore id della chiave primaria], quindi in questo caso se chiamiamo il metodo save() o persist() allora inserirà il record nel database normalmente Ma la cosa è udibile, il metodo save() può restituire il valore id della chiave primaria che è generato dalla sospensione e possiamo vederlo da

 long s = session.save(k); 

In questo stesso caso, persist() non restituirà mai alcun valore al client.

Ho trovato un buon esempio che mostra le differenze tra tutti i metodi di salvataggio in modalità ibernazione:

http://www.journaldev.com/3481/hibernate-session-merge-vs-update-save-saveorupdate-persist-example

In breve, secondo il link qui sopra:

salvare()

  • Possiamo invocare questo metodo al di fuori di una transazione. Se usiamo questo senza transazione e abbiamo una cascata tra entity framework, solo l’ quadro primaria viene salvata a meno che non si svuota la sessione.
  • Quindi, se ci sono altri oggetti mappati dall’object primario, vengono salvati al momento della transazione o quando si scarica la sessione.

persistere()

  • È simile all’utilizzo di save () nella transazione, quindi è sicuro e si prende cura degli oggetti in cascata.

saveOrUpdate ()

  • Può essere usato con o senza la transazione, e proprio come save (), se è usato senza la transazione, le entity framework mappate non verranno salvate, mentre noi scarichiamo la sessione.

  • Risultati in inserimento o aggiornamento di query in base ai dati forniti. Se i dati sono presenti nel database, viene eseguita la query di aggiornamento.

aggiornare()

  • L’aggiornamento Hibernate dovrebbe essere usato dove sappiamo che stiamo solo aggiornando le informazioni sull’ quadro. Questa operazione aggiunge l’object quadro al contesto persistente e ulteriori modifiche vengono tracciate e salvate quando viene eseguito il commit della transazione.
  • Quindi, anche dopo aver chiamato l’aggiornamento, se impostiamo valori nell’ quadro, questi verranno aggiornati quando la transazione viene eseguita.

merge ()

  • L’unione in letargo può essere utilizzata per aggiornare i valori esistenti, tuttavia questo metodo crea una copia dall’object quadro passato e la restituisce. L’object restituito fa parte del contesto persistente e viene tracciato per qualsiasi modifica, l’object passato non viene tracciato. Questa è la principale differenza con l’unione () di tutti gli altri metodi.

Anche per esempi pratici di tutti questi, fai riferimento al link che ho citato sopra, mostra esempi per tutti questi diversi metodi.

Tieni presente che se chiami un aggiornamento su un object staccato, ci sarà sempre un aggiornamento fatto nel database se hai cambiato l’object o meno. Se non è quello che vuoi, dovresti usare Session.lock () con LockMode.None.

È necessario chiamare l’aggiornamento solo se l’object è stato modificato al di fuori dell’ambito della sessione corrente (in modalità distaccata).

Nessuna delle seguenti risposte è corretta. Tutti questi metodi sembrano uguali, ma in pratica fanno cose assolutamente diverse. È difficile dare brevi commenti. Meglio dare un link alla documentazione completa su questi metodi: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/objectstate.html