Ibernazione: differenza tra session.get e session.load


88

Dall'API, ho potuto vedere che ha qualcosa a che fare con il proxy. Ma non sono riuscito a trovare molte informazioni su proxy e non capisco la differenza tra chiamata session.gete session.load. Qualcuno potrebbe spiegarmi o indirizzarmi a una pagina di riferimento?

Grazie!!

Risposte:


117

Dal forum di Hibernate :

Questo dal libro Hibernate in Action. Bravo leggere questo ..


Recupero di oggetti in base all'identificatore Il seguente frammento di codice Hibernate recupera un oggetto Utente dal database:

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

Il metodo get () è speciale perché l'identificatore identifica in modo univoco una singola istanza di una classe. Quindi è comune per le applicazioni utilizzare l'identificatore come una comoda maniglia per un oggetto persistente. Il recupero per identificatore può utilizzare la cache durante il recupero di un oggetto, evitando un accesso al database se l'oggetto è già memorizzato nella cache. Hibernate fornisce anche un metodo load ():

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

Il metodo load () è più vecchio; get () è stato aggiunto all'API di Hibernate a causa della richiesta dell'utente. La differenza è banale:

Se load () non riesce a trovare l'oggetto nella cache o nel database, viene generata un'eccezione. Il metodo load () non restituisce mai null. Il metodo get () restituisce null se l'oggetto non può essere trovato.

Il metodo load () può restituire un proxy invece di una vera istanza persistente. Un proxy è un segnaposto che attiva il caricamento dell'oggetto reale quando vi si accede per la prima volta; D'altra parte, get () non restituisce mai un proxy. Scegliere tra get () e load () è facile: se sei certo che l'oggetto persistente esista e che la non esistenza sarebbe considerata eccezionale, load () è una buona opzione. Se non sei sicuro che esista un'istanza persistente con l'identificatore fornito, usa get () e verifica il valore restituito per vedere se è nullo. L'uso di load () ha un'ulteriore implicazione: l'applicazione può recuperare un riferimento valido (un proxy) a un'istanza persistente senza premere il database per recuperare il suo stato persistente. Quindi load () potrebbe non generare un'eccezione quando non trova l'oggetto persistente nella cache o nel database; l'eccezione verrebbe lanciata in seguito, quando si accede al proxy. Ovviamente, il recupero di un oggetto tramite identificatore non è flessibile quanto l'utilizzo di query arbitrarie.


1
Sto eseguendo il debug di un problema in questo momento in cui session.Get <T> () sta restituendo un proxy!
Kent Boogaart

7
Molte grazie! La parte relativa al denaro per me era: "Se load () non riesce a trovare l'oggetto nella cache o nel database, viene generata un'eccezione. Il metodo get () restituisce null se l'oggetto non può essere trovato."
Chris

15
Il JavaDoc per Session.get dice: Restituisce l'istanza persistente della data classe di entità con l'identificativo specificato, o null se non esiste tale istanza persistente. (Se l'istanza, o un proxy per l'istanza, è già associata alla sessione, restituisci quell'istanza o proxy.) Quindi la sezione del libro che dice: "D'altra parte, get () non restituisce mai un proxy." non è corretto.
Vicky

se stai usando una strategia di gestione delle transazioni con i tuoi daos, potresti preferire get (). altrimenti il ​​chiamante dovrà essere eseguito anche nel contesto di una sessione di ibernazione aperta nel caso in cui load () restituisca un proxy. ad esempio, se stai usando MVC, il tuo controller potrebbe eseguire dao.load () e quindi lanciare un'eccezione quando si tenta di accedere all'oggetto proxy in un secondo momento se non c'è una sessione valida. fare dao.get () restituirà l'oggetto effettivo al controller indipendentemente dalla sessione (supponendo che esista)
dev

Il problema descritto da @Vicky può causare mal di testa e non ne vedo alcun vantaggio. In alcuni casi ho anche bisogno dell'identificatore per ulteriori query parametrizzate. Ma poiché un proxy dell'oggetto è già nella sessione, il getter dell'identificatore restituisce null. Perché recuperano il proxy invece dell'istanza reale se quel proxy è nella sessione?
djmj

15

Bene, almeno in nhibernate, session.Get (id) caricherà l'oggetto dal database, mentre session.Load (id) crea solo un oggetto proxy senza lasciare il tuo server. Funziona proprio come ogni altra proprietà con caricamento lento nei tuoi POCO (o POJO :). È quindi possibile utilizzare questo proxy come riferimento all'oggetto stesso per creare relazioni, ecc.

Pensa come avere un oggetto che conserva solo l'Id e che caricherà il resto se ne avrai bisogno. Se lo passi solo per creare relazioni (come FK), l'id è tutto ciò di cui avrai bisogno.


quindi vuoi dire che load (id) prima colpirà il database per verificare che sia un id valido o meno e poi restituirà l'oggetto proxy e quando si accede alle proprietà di questo oggetto colpisce di nuovo il database? non è uno scenario improbabile? due query per caricare un singolo oggetto?
faisalbhagat

No, load (id) non convaliderà affatto l'id, quindi nessun round trip al DB. Usalo solo quando sei sicuro di essere sicuro che sia valido.
Jorge Alves,

9

session.load () restituirà sempre un "proxy" (termine Hibernate) senza colpire il database. In Hibernate, il proxy è un oggetto con il valore identificativo specificato, le sue proprietà non sono ancora inizializzate, sembra solo un oggetto falso temporaneo. Se non viene trovata alcuna riga, verrà generata un'eccezione ObjectNotFoundException.

session.get () colpisce sempre il database e restituisce l'oggetto reale, un oggetto che rappresenta la riga del database, non il proxy. Se non viene trovata alcuna riga, restituisce null.

Anche le prestazioni con questi metodi rendono diff. tra due...


3

Un punto extra in più:

get metodo della classe Hibernate Session restituisce null se l'oggetto non viene trovato nella cache così come nel database. mentre il metodo load () genera ObjectNotFoundException se l'oggetto non viene trovato nella cache e nel database ma non restituisce mai null.


2

Una conseguenza indiretta dell'utilizzo di "load" invece di "get" è che il blocco ottimistico utilizzando un attributo di versione potrebbe non funzionare come ci si aspetterebbe. Se un caricamento crea semplicemente un proxy e non legge dal database, la proprietà version non viene caricata. La versione verrà caricata solo quando / se successivamente si fa riferimento a una proprietà sull'oggetto, attivando una selezione. Nel frattempo, un'altra sessione può aggiornare l'oggetto e la tua sessione non avrà la versione originale necessaria per eseguire il controllo ottimistico del blocco, quindi l'aggiornamento della tua sessione sovrascriverà l'aggiornamento dell'altra sessione senza alcun avviso.

Ecco un tentativo di abbozzare questo scenario con due sessioni che lavorano con un oggetto con lo stesso identificatore. La versione iniziale per l'oggetto in 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]

Vogliamo effettivamente che il commit della sessione 1 fallisca con un'eccezione di blocco ottimistica, ma qui avrà successo.

Usare "get" invece di "load" aggira il problema, perché get emetterà immediatamente una selezione ei numeri di versione verranno caricati al momento giusto per il controllo ottimistico del blocco.


0

Inoltre dobbiamo stare attenti durante l'utilizzo di load poiché genererà un'eccezione se l'oggetto non è presente. Dobbiamo usarlo solo quando siamo sicuri che l'oggetto esiste.


0

Un'eccellente spiegazione si trova su http://www.mkyong.com/hibernate/different-between-session-get-and-session-load
session.load ():
restituirà sempre un "proxy" (termine Hibernate) senza colpire il database.
In Hibernate, il proxy è un oggetto con il valore identificativo specificato, le sue proprietà non sono ancora inizializzate, sembra solo un oggetto falso temporaneo.
Restituirà sempre un oggetto proxy con il valore di identità specificato, anche se il valore di identità non esiste nel database. Tuttavia, quando si tenta di inizializzare un proxy recuperando le sue proprietà dal database, verrà raggiunto il database con l'istruzione select. Se non viene trovata alcuna riga, verrà generata un'eccezione ObjectNotFoundException.
session.get ():
Colpisce sempre il database (se non viene trovato nella cache) e restituisce l'oggetto reale, un oggetto che rappresenta la riga del database, non il proxy.
Se non viene trovata alcuna riga, restituisce null.


0

load () non riesce a trovare l'oggetto dalla cache o dal database, viene generata un'eccezione e il metodo load () non restituisce mai null.

Il metodo get () restituisce null se l'oggetto non può essere trovato. Il metodo load () può restituire un proxy invece di una vera istanza persistente get () non restituisce mai un proxy.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.