Hibernate: spremanje, ustrajanje, ažuriranje, spajanje, saveOrUpdate

1. Uvod

U ovom ćemo članku razgovarati o razlikama između nekoliko metoda Sjednica sučelje: uštedjeti, ustrajati, ažuriranje, sjediniti, saveOrUpdate.

Ovo nije uvod u Hibernate i već biste trebali znati osnove konfiguracije, objektno-relacijskog mapiranja i rada s instancama entiteta. Za uvodni članak o hibernaciji posjetite naš vodič o hibernaciji 4 s proljećem.

2. Sesija kao provedba konteksta ustrajnosti

The Sjednica sučelje ima nekoliko metoda koje na kraju rezultiraju spremanjem podataka u bazu podataka: ustrajati, uštedjeti, ažuriranje, sjediniti, saveOrUpdate. Da bismo razumjeli razliku između ovih metoda, prvo moramo razgovarati o svrsi Sjednica kao kontekst postojanosti i razlika između stanja entitetskih instanci u odnosu na Sjednica.

Također bismo trebali razumjeti povijest razvoja hibernacije koja je dovela do nekih djelomično dupliciranih API metoda.

2.1. Upravljanje instancama entiteta

Osim samog objektno-relacijskog mapiranja, jedan od problema koje je Hibernate trebao riješiti je i problem upravljanja entitetima tijekom izvođenja. Pojam "konteksta postojanosti" hibernatsko je rješenje ovog problema. Kontekst postojanosti može se smatrati spremnikom ili predmemorijom prve razine za sve objekte koje ste učitali ili spremili u bazu podataka tijekom sesije.

Sesija je logična transakcija, čije su granice definirane poslovnom logikom vaše aplikacije. Kada radite s bazom podataka kroz kontekst trajnosti i sve su instance vašeg entiteta povezane s tim kontekstom, uvijek biste trebali imati jednu instancu entiteta za svaki zapis baze podataka s kojim ste komunicirali tijekom sesije.

U hibernaciji kontekst postojanosti predstavlja org.hibernate.Sjednica primjer. Za JPA je to javax.persistence.EntityManager. Kada koristimo Hibernate kao JPA pružatelja usluga i radimo putem EntityManager sučelje, implementacija ovog sučelja u osnovi prekriva osnovno Sjednica objekt. Međutim, Hibernate Sjednica pruža bogatije sučelje s više mogućnosti pa je ponekad korisno raditi s njim Sjednica izravno.

2.2. Države entiteta

Bilo koja instanca entiteta u vašoj aplikaciji pojavljuje se u jednom od tri glavna stanja u odnosu na Sjednica kontekst postojanosti:

  • prolazan - ova instanca nije, niti je ikad bila povezana s a Sjednica; ova instanca nema odgovarajuće retke u bazi podataka; to je obično samo novi objekt koji ste stvorili za spremanje u bazu podataka;
  • uporan - ova je instanca povezana s jedinstvenim Sjednica objekt; nakon ispiranja Sjednica za bazu podataka, ovaj entitet zajamčeno ima odgovarajući dosljedni zapis u bazi podataka;
  • odvojena - ova je instanca jednom dodana u Sjednica (u uporan država), ali sada nije; instanca uđe u ovo stanje ako je izbacite iz konteksta, izbrišete ili zatvorite Sesiju ili stavite instancu kroz postupak serializacije / deserializacije.

Evo pojednostavljenog dijagrama stanja s komentarima na Sjednica metode koje čine tranzicije države.

Kada je instanca entiteta u uporan stanja, sve promjene koje napravite na mapiranim poljima ove instance primijenit će se na odgovarajuće zapise baze podataka i polja nakon ispiranja Sjednica. The uporan Primjerak se može smatrati "mrežnim", dok odvojena instanca je postala "offline" i ne prati se zbog promjena.

To znači da kada mijenjate polja a uporan objekt, ne morate zvati uštedjeti, ažuriranje ili bilo koja od tih metoda za donošenje ovih promjena u bazu podataka: sve što trebate je izvršiti transakciju ili isprati ili zatvoriti sesiju kada završite s njom.

2.3. Sukladnost sa JPA specifikacijom

Hibernate je bila najuspješnija implementacija Java ORM-a. Nije ni čudo što je Hibernate API jako utjecao na specifikaciju Java persistent API (JPA). Nažalost, bilo je i mnogo razlika: neke velike, neke suptilnije.

Da bi djelovao kao provedba JPA standarda, Hibernate API-ji morali su biti revidirani. Nekoliko je metoda dodano sučelju Session kako bi se podudaralo sa sučeljem EntityManager. Te metode služe u istu svrhu kao i "izvorne" metode, ali udovoljavaju specifikaciji i stoga imaju neke razlike.

3. Razlike između operacija

Važno je od početka shvatiti da sve metode (ustrajati, uštedjeti, ažuriranje, sjediniti, saveOrUpdate) ne rezultiraju odmah odgovarajućim SQL-om AŽURIRANJE ili UMETNUTI izjave. Stvarno spremanje podataka u bazu podataka događa se prilikom izvršavanja transakcije ili ispiranja Sjednica.

Spomenute metode u osnovi upravljaju stanjem entitetskih instanci prelazeći ih između različitih stanja tijekom životnog ciklusa.

Kao primjer entiteta upotrijebit ćemo jednostavan entitet mapiran s bilješkama Osoba:

@ Entiteta javna klasa Osoba {@Id @GeneratedValue private Long id; privatni naziv niza; // ... geteri i postavljači}

3.1. Ustrajati

The ustrajati metoda namijenjena je dodavanju nove instance entiteta u kontekst postojanosti, tj. prijelazu instance iz prolazne u uporan država.

Obično ga zovemo kada želimo dodati zapis u bazu podataka (trajati instanca entiteta):

Osoba osoba = nova osoba (); person.setName ("Ivan"); session.persist (osoba);

Što se događa nakon ustrajati metoda se zove? The osoba objekt je prešao iz prolazan do uporan država. Objekt je sada u kontekstu postojanosti, ali još nije spremljen u bazu podataka. Generacija UMETNUTI Izjave će se dogoditi tek nakon izvršavanja transakcije, ispiranja ili zatvaranja sesije.

Primijetite da ustrajati metoda ima poništiti povratni tip. Djeluje na proslijeđenom objektu "na mjestu", mijenjajući svoje stanje. The osoba varijabla se odnosi na stvarni trajni objekt.

Ova metoda je kasniji dodatak sučelju Session. Glavna značajka koja razlikuje ovu metodu je da je u skladu s JSR-220 specifikacijom (postojanost EJB). Semantika ove metode strogo je definirana u specifikaciji koja u osnovi navodi da:

  • a prolazan instanca postaje uporan (i operacija se kaskadira na sve svoje odnose s kaskada = PERSIST ili kaskada = SVE),
  • ako je instanca već uporan, tada ovaj poziv nema učinka za ovu konkretnu instancu (ali se i dalje kaskadira u odnosima s kaskada = PERSIST ili kaskada = SVE),
  • ako je instanca odvojena, trebali biste očekivati ​​iznimku, bilo prilikom pozivanja ove metode, bilo prilikom predavanja ili ispiranja sesije.

Primijetite da ovdje nema ničega što se tiče identifikatora instance. Specifikacija ne navodi da će se id generirati odmah, bez obzira na strategiju generiranja id-a. Specifikacija za ustrajati metoda omogućuje implementaciji da izdaje izjave za generiranje id-a pri urezivanju ili ispiranju, a zajamčeno je da id nije null nakon poziva ove metode, pa se ne biste trebali oslanjati na njega.

Ovu metodu možete nazvati na već uporan primjerice, i ništa se ne događa. Ali ako pokušate ustrajati a odvojena Primjerice, provedba je dužna izuzeti. U sljedećem primjeru mi ustrajati entitet, iseliti to iz konteksta pa postaje odvojena, a zatim pokušajte ustrajati opet. Drugi poziv session.persist () uzrokuje iznimku, pa sljedeći kod neće raditi:

Osoba osoba = nova osoba (); person.setName ("Ivan"); session.persist (osoba); sjednica.evict (osoba); session.persist (osoba); // PersistenceException!

3.2. Uštedjeti

The uštedjeti metoda je „izvorna“ hibernacija koja nije u skladu s JPA specifikacijom.

Njegova je svrha u osnovi ista kao ustrajati, ali ima različite detalje implementacije. Dokumentacija za ovu metodu striktno navodi da ona nastavlja s instancom, "prvo dodjeljujući generirani identifikator". Zajamčena metoda vraća metodu Serijalizirati vrijednost ovog identifikatora.

Osoba osoba = nova osoba (); person.setName ("Ivan"); Long id = (Long) session.save (person);

Učinak spremanja već ustrajane instance jednak je kao i kod ustrajati. Razlika dolazi kada pokušate spasiti a odvojena primjer:

Osoba osoba = nova osoba (); person.setName ("Ivan"); Long id1 = (Long) session.save (person); sjednica.evict (osoba); Long id2 = (Long) session.save (person);

The id2 varijabla će se razlikovati od id1. Poziv za spremanje na odvojena instanca stvara novi uporan instanci i dodjeljuje joj novi identifikator, što rezultira duplikatom zapisa u bazi podataka nakon izvršavanja ili ispiranja.

3.3. Sjediniti

Glavna namjera sjediniti metoda je ažuriranje a uporan instance entiteta s novim vrijednostima polja iz a odvojena instanca entiteta.

Na primjer, pretpostavimo da imate RESTful sučelje s metodom za dohvaćanje JSON-serializiranog objekta prema njegovom ID-u pozivatelju i metodom koja od ažuriratelja prima ažuriranu verziju ovog objekta. Entitet koji je prošao kroz takvu serializaciju / deserializaciju pojavit će se u a odvojena država.

Nakon deserializacije ove instance entiteta, morate dobiti uporan instance entiteta iz konteksta postojanosti i ažurirajte njegova polja novim vrijednostima iz toga odvojena primjer. Dakle sjediniti metoda čini upravo to:

  • pronalazi instancu entiteta pomoću id-a preuzetog iz proslijeđenog objekta (dohvaća se postojeća instanca entiteta iz konteksta postojanosti ili nova instanca učitana iz baze podataka);
  • kopira polja iz proslijeđenog objekta u ovu instancu;
  • vraća novo ažuriranu instancu.

U sljedećem primjeru mi iseliti (odvojiti) spremljeni entitet od konteksta, promijeniti Ime polje, a zatim sjediniti the odvojena entitet.

Osoba osoba = nova osoba (); person.setName ("Ivan"); session.save (osoba); sjednica.evict (osoba); person.setName ("Marija"); Osoba mergedPerson = (Osoba) session.merge (osoba);

Imajte na umu da sjediniti metoda vraća objekt - to je spojeniOsoba objekt koji je učitan u kontekst postojanosti i ažuriran, a ne osoba objekt koji ste proslijedili kao argument. To su dva različita predmeta, i osoba objekt obično treba odbaciti (u svakom slučaju, nemojte računati da je povezan s kontekstom postojanosti).

Kao i sa ustrajati metoda, sjediniti metoda je navedena u JSR-220 da bi imala određenu semantiku na koju se možete osloniti:

  • ako je entitet odvojena, kopira se na postojeću uporan entitet;
  • ako je entitet prolazan, kopira se na novostvoreni uporan entitet;
  • ova operacija kaskade za sve odnose s kaskada = STIPI ili kaskada = SVE mapiranje;
  • ako je entitet uporan, tada ovaj poziv metode na njega nema utjecaja (ali kaskadiranje se i dalje odvija).

3.4. ažuriranje

Kao i sa ustrajati i uštedjeti, ažuriranje metoda je "izvorna" hibernacija koja je bila prisutna puno prije sjediniti dodana je metoda. Njegova se semantika razlikuje u nekoliko ključnih točaka:

  • djeluje na proslijeđeni objekt (njegov povratni tip je poništiti); the ažuriranje metoda prelazi proslijeđeni objekt iz odvojena do uporan država;
  • ova metoda donosi iznimku ako je proslijedite a prolazan entitet.

U sljedećem primjeru mi uštedjeti objekt, dakle iseliti (odvojite ga) od konteksta, a zatim promijenite njegov Ime i nazovite ažuriranje. Primijetite da ne stavljamo rezultat ažuriranje rad u zasebnoj varijabli, jer ažuriranje odvija se na osoba sam objekt. U osnovi ponovno pridružujemo postojeću instancu entiteta kontekstu postojanosti - nešto što nam JPA specifikacija ne dopušta.

Osoba osoba = nova osoba (); person.setName ("Ivan"); session.save (osoba); sjednica.evict (osoba); person.setName ("Marija"); session.update (osoba);

Pokušavam nazvati ažuriranje na a prolazan instanca rezultirat će iznimkom. Sljedeće neće raditi:

Osoba osoba = nova osoba (); person.setName ("Ivan"); session.update (osoba); // PersistenceException!

3.5. SaveOrUpdate

Ova se metoda pojavljuje samo u Hibernate API-ju i nema svog standardiziranog pandana. Slično ažuriranje, također se može koristiti za ponovno spajanje slučajeva.

Zapravo, unutarnje DefaultUpdateEventListener klasa koja obrađuje ažuriranje metoda je podrazred od DefaultSaveOrUpdateListener, samo nadjačavanje neke funkcionalnosti. Glavna razlika od saveOrUpdate metoda je da ne donosi iznimku kada se primijeni na prolazan primjer; umjesto toga, čini ovo prolazan primjer uporan. Sljedeći će kôd nastaviti s novostvorenom instancom Osoba:

Osoba osoba = nova osoba (); person.setName ("Ivan"); session.saveOrUpdate (osoba);

O ovoj metodi možda mislite kao o univerzalnom alatu za izradu predmeta uporan bez obzira na njegovo stanje da li je prolazan ili odvojena.

4. Što koristiti?

Ako nemate nikakvih posebnih zahtjeva, u pravilu se trebate držati znaka ustrajati i sjediniti metode, jer su standardizirane i zajamčeno udovoljavaju JPA specifikaciji.

Oni su također prijenosni u slučaju da se odlučite prebaciti na drugog pružatelja trajnosti, ali ponekad se mogu činiti ne toliko korisnima kao "izvorne" metode hibernacije, uštedjeti, ažuriranje i saveOrUpdate.

5. Zaključak

Raspravljali smo o namjeni različitih metoda hibernacijske sesije u vezi s upravljanjem trajnim entitetima u vrijeme izvođenja. Saznali smo kako ove metode tranziciraju instance entiteta kroz njihov životni ciklus i zašto neke od tih metoda dupliciraju funkcionalnost.

Izvorni kôd članka dostupan je na GitHubu.