JPA „EntityManager“: kodėl naudokite () daugiau nei sujungus ()?

EntityManager.merge() gali įterpti naujus objektus ir atnaujinti esamus.

Kodėl naudoti persist() (kuris gali sukurti tik naujus objektus)?

840
01 июля '09 в 19:03 2009-07-01 19:03 Aaron Digulla yra nustatytas liepos 01'09 19:03 2009-07-01 19:03
@ 15 atsakymų

Bet kokiu atveju pridėkite objektą į „PersistenceContext“, o skirtumas yra tas, ką darote su objektu vėliau.

Išlaikyti užima subjekto pavyzdį, prideda jį prie konteksto ir valdo tą egzempliorių (t. Y. Būsimų objektų atnaujinimai bus stebimi).

Sujungimas sukuria naują jūsų objekto egzempliorių, kopijuoja būseną iš pateikto objekto ir valdo naują kopiją. Pavyzdys, kuriuo jūs einate, nebus valdomas (bet kokie pakeitimai, kuriuos atliksite, nebus sandorio dalis - nebent jūs vėl sujungsite).

Galbūt mėginio kodas padės.

 MyEntity e = new MyEntity(); // scenario 1 // tran starts em.persist(e); e.setSomeField(someValue); // tran ends, and the row for someField is updated in the database // scenario 2 // tran starts e = new MyEntity(); em.merge(e); e.setSomeField(anotherValue); // tran ends but the row for someField is not updated in the database // (you made the changes *after* merging) // scenario 3 // tran starts e = new MyEntity(); MyEntity e2 = em.merge(e); e2.setSomeField(anotherValue); // tran ends and the row for someField is updated // (the changes were made to e2, not e) 

1 ir 3 scenarijai yra maždaug lygūs, tačiau yra situacijų, kai norite naudoti 2 scenarijų.

1456 m
01 июля '09 в 21:28 2009-07-01 21:28 Atsakymą pateikė Mike liepos 1 d., 09:21, 2009-07-01 21:28

Išlikti ir sujungti yra skirti dviem skirtingiems tikslams (jie nėra alternatyvūs).

(redaguota siekiant išplėsti skirtumus)

išlieka:

  • Į duomenų bazę įterpkite naują registrą
  • Pridėkite objektą prie įmonės valdytojo.

sujungti:

  • Raskite pridedamą objektą su tuo pačiu identifikatoriumi ir jį atnaujinkite.
  • Jei atnaujinimas yra ir grąžina jau pridedamą objektą.
  • Jei neegzistuoja, į duomenų bazę įdėkite naują registrą.
Veiksmingumas

išlieka ():

  • Gali būti veiksmingiau į duomenų bazę įterpti naują registrą nei sujungti ().
  • Ji nedubliuoja pradinio objekto.

išlieka () semantika:

  • Tai užtikrina, kad įterpiate ir netinkamai atnaujinate.

Pavyzdys:

 { AnyEntity newEntity; AnyEntity nonAttachedEntity; AnyEntity attachedEntity; // Create a new entity and persist it newEntity = new AnyEntity(); em.persist(newEntity); // Save 1 to the database at next flush newEntity.setValue(1); // Create a new entity with the same Id than the persisted one. AnyEntity nonAttachedEntity = new AnyEntity(); nonAttachedEntity.setId(newEntity.getId()); // Save 2 to the database at next flush instead of 1!!! nonAttachedEntity.setValue(2); attachedEntity = em.merge(nonAttachedEntity); // This condition returns true // merge has found the already attached object (newEntity) and returns it. if(attachedEntity==newEntity) { System.out.print("They are the same object!"); } // Set 3 to value attachedEntity.setValue(3); // Really, now both are the same object. Prints 3 System.out.println(newEntity.getValue()); // Modify the un attached object has no effect to the entity manager // nor to the other objects nonAttachedEntity.setValue(42); } 

Tokiu atveju yra tik vienas pridedamas objektas bet kuriam ūkio subjekto valdytojo registrui.

sujungti () objektui, kurio identifikatorius yra toks:

 AnyEntity myMerge(AnyEntity entityToSave) { AnyEntity attached = em.find(AnyEntity.class, entityToSave.getId()); if(attached==null) { attached = new AnyEntity(); em.persist(attached); } BeanUtils.copyProperties(attached, entityToSave); return attached; } 

Nors jungiantis prie „MySQL“ sujungimas () gali būti lygiai toks pat veiksmingas kaip ir toliau () naudojant „INSERT“ skambutį pasirinkus „ON DUPLICATE KEY UPDATE“, JPA yra labai aukšto lygio programavimas, ir jūs negalite daryti prielaidos, kad taip bus visur.

151
11 июня '13 в 14:04 2013-06-11 14:04 atsakymą pateikė Josep Panadero birželio 11 d., 13 val. 14:04. 2013-06-11 14:04

Jei naudojate nurodytą generatorių, naudodami susiliejimą vietoj nuolatinių, gali atsirasti pernelyg didelė SQL išraiška , kuri paveiks našumą.

Be to, valdomų objektų sujungimo skambutis taip pat yra klaida, nes valdomus objektus automatiškai valdo sulaikytosios veiksenos režimas, o jų būsena sinchronizuojama su duomenų bazės įrašu, naudojant purviną tikrinimo variklį, kai išplaunamas išsaugojimo kontekstas .

Norėdami suprasti, kaip visa tai veikia, pirmiausia turite žinoti, kad „Hibernate“ perkelia kūrėjo mąstymą iš SQL į objektų būsenos perėjimus .

Kai „Hibernate“ aktyviai valdo objektą, visi pakeitimai bus automatiškai perduodami duomenų bazėje.

„Hibernate“ valdo pridedamus objektus. Tačiau tam, kad subjektas taptų valdomas, jis turi būti teisinga.

Pirma, turime apibrėžti visus subjektus:

  • Naujas (pereinamasis)

    Naujai sukurtas objektas, kuris niekada nebuvo susietas su „Hibernate“ Session (taip pat Persistence Context kaip „ Persistence Context ) ir nėra rodomas jokioje duomenų bazės lentelėje, eilutė laikoma naujos (laikinos) būsenos.

    Norint tapti nuolatiniu, turime arba aiškiai paskambinti „ EntityManager#persist metodu, arba naudoti tranzitinį atkaklumo mechanizmą.

  • Nuolatinis (kontroliuojamas)

    Nuolatinis objektas yra susietas su duomenų bazės lentelės eilute ir yra valdomas pagal dabartinį atkaklumo kontekstą. Bet kokie tokio objekto pakeitimai bus aptikti ir platinami duomenų bazėje (sesijos sesijos metu). Su „Hibernate“, mums nebereikės vykdyti instrukcijų „INSERT / UPDATE / DELETE“. Sulaikytosios veiksenos operacijoms įrašyti naudojamas darbo stilius , o pakeitimai sinchronizuojami paskutiniu metu svarbiausiu dabartinės Session momentu.

  • atskirai

    Kai tik bus išsaugotas šiuo metu veikiantis išsaugojimo kontekstas, visi anksčiau valdomi objektai atjungiami. Vėlesni pakeitimai nebebus stebimi, o automatinė duomenų bazės sinchronizacija nebus.

    Jei norite susieti vieną objektą su aktyvia sulaikytosios veiksenos sesija, galite pasirinkti iš šių parinkčių:

    • Įrašymas

      Sulaikytosios veiksenos (bet ne JPA 2.1) palaiko prisijungimą per sesijos atnaujinimo metodą #. Sulaikytosios sesijos sesija gali susieti tik vieną Entity objektą tam tikrai duomenų bazės eilutei. Taip yra dėl to, kad išsaugojimo kontekstas veikia kaip atmintis atmintyje (pirmojo lygio talpykla), ir tik viena reikšmė (subjektas) yra susieta su tam tikru raktu (subjekto tipas ir duomenų bazės identifikatorius). Objektas gali būti prijungtas tik tada, jei nėra kito JVM objekto (atitinkančio tą pačią duomenų bazės eilutę), kuri jau susieta su dabartine sulaikytosios veiksenos sesija.

    • šlifavimas

    Susijungimas ketina nukopijuoti nuotolinio objekto (šaltinio) būseną į valdomo objekto (paskirties) egzempliorių. Jei sujungtas objektas dabartinėje sesijoje nėra lygiavertis, vienas iš jų bus atkurtas iš duomenų bazės. Atskiro objekto egzempliorius ir toliau išliks net po sujungimo operacijos.

  • Pašalinta

    Nors JPA reikalauja, kad valdomi objektai leistų ištrinti duomenis, Hibernate taip pat gali ištrinti atskirus elementus (bet tik skambindami ištrinimo sesijos metodu #). Ištrintas objektas planuojamas tik ištrynimui, o faktinė duomenų bazė DELETE bus vykdoma sesijos sesijos metu.

Norėdami geriau suprasti JPA būsenos perėjimus, galite vizualizuoti šią diagramą:

2019

108
11 мая '15 в 16:00 2015-05-11 16:00 atsakymą Vladas Mihalcea pateikė gegužės 15 d., 15 val., 15.00 val. 2015-05-11 16:00

Aš pastebėjau, kad kai aš naudoju em.merge , aš gavau SELECT kiekvienam INSERT , net jei man nebuvo lauko, kurį JPA sukūrė man - pagrindinis raktų laukas buvo UUID, kurį nustatiau sau. em.persist(myEntityObject) į em.persist(myEntityObject) ir gavau tik INSERT instrukcijas.

37
19 янв. Atsakyti Sarah Vessels Jan 19 2012-01-19 00:14 '12 at 0:14 2012-01-19 00:14

JPA specifikacijoje teigiama, kad apie persist() .

Jei X yra atskiras objektas, „ EntityExistsException gali būti išmestas, kai išsaugoma operacija, arba „ EntityExistsException ar kitą „ PersistenceException gali būti išmestas skalavimo ar fiksavimo metu.

Taigi, naudojant persist() būtų tikslinga, jei objektas nebūtų atskiras objektas. Galbūt norite, kad kodas sukeltų PersistenceException , kad jis neveiktų greitai.

Nors specifikacija yra fuzzy , persist() gali nustatyti @GeneratedValue @Id objektui. merge() turi turėti objektą su jau sukurtu @Id .

27
11 марта '12 в 20:23 2012-03-11 20:23 atsakymas pateikiamas Raedwaldui kovo 11 d., 12 val

Išsaugomi kai kurie duomenys apie susijungimą, kuris padės jums naudoti susijungimą:

Grąžinamos valdomos instancijos, išskyrus pradinį objektą, grąžinimas yra svarbi sujungimo proceso dalis. Jei objekto egzempliorius, turintis tą patį identifikatorių, jau egzistuoja atkaklumo kontekste, paslaugų teikėjas perrašys savo būseną su susijungusio objekto būsena, tačiau jau esanti valdoma versija turi būti grąžinta klientui, kad jis galėtų būti naudojamas. Jei tiekėjas neatnaujina darbuotojo egzemplioriaus atkaklumo kontekste, visos nuorodos į šią instanciją taps nesuderinamos su nauja valstybe, kuri bus sujungta.

Kai sujungimas () yra iškviestas į naują objektą, jis elgiasi panašiai kaip ir toliau (). Jis prideda objektą atkaklumo kontekste, bet vietoj to, kad pridėtų pradinį objekto egzempliorių, jis sukuria naują, kuris kopijuoja ir tvarko šį atvejį. Kopija, sukurta naudojant susijungimo () operaciją, išlieka taip, tarsi būtų pasikartojantis () metodas.

Jei yra ryšių, sujungimo () operacija bandys atnaujinti valdomą objektą, kad nukreiptų į valdomų objektų versijas, kurias nurodo individualus objektas. Jei objektas yra susijęs su objektu, kuris neturi nuolatinio tapatybės, sujungimo rezultatas yra neapibrėžtas. Kai kurie paslaugų teikėjai gali leisti valdomai kopijai nukreipti į kintamą objektą, o kiti gali iš karto pašalinti išimtį. Sujungimo () operacija pasirinktinai gali būti pakopinta šiais atvejais, kad būtų išvengta išimties atsiradimo. Šiame skyriuje mes peržiūrėsime sujungimo pakopą (). Jei sujungta sąjunga nukreipia į nuotolinį objektą, neįtraukiama „IllegalArgumentException“.

Keičiamumas yra ypatingas atvejis susijungimo operacijoje. Jei prieš pradedant jį atsiimti subjektui nebuvo inicijuotas tingus santykių įkrovimas, šis ryšys bus ignoruojamas, kai objektas bus sujungtas. Jei nuoroda buvo inicijuota valdymu, o tada, kai objektas buvo atjungtas, nustatomas nulis, taip pat bus susieta valdomo objekto versija, kuri bus pašalinta sujungimo metu. "

Visa tai buvo paimta iš „Pro JPA 2“ „Mike Keith“ ir „Merrick Schniariol“ „Java Persistence API API“ įsisavinimo 6. skyrius. Komandos ir susiliejimo skyrius. Ši knyga yra antroji JPA autorių knyga. Aš tikrai rekomenduoju skaityti šią knygą tiems, kurie bus rimtai susiję su JPA, ir apgailestauju, kad anonimiškai paskelbiau savo pirmąjį atsakymą.

16
05 окт. Churshed Salimov atsakymas 05 spalis 2012-10-05 16:00 „12 at 4:00 val. 2012-10-05 16:00

Yra keletas kitų skirtumų tarp merge ir persist (dar kartą išvardysiu tuos, kurie jau buvo paskelbti čia):

D1. merge nekontroliuoja perduoto subjekto, bet grąžina kitą valdomą pavyzdį. kita vertus, kontroliuoja perduotą subjektą:

 //MERGE: passedEntity remains unmanaged, but newEntity will be managed Entity newEntity = em.merge(passedEntity); //PERSIST: passedEntity will be managed after this em.persist(passedEntity); 

D2. Jei ištrinsite objektą ir tada nuspręsite įrašyti objektą atgal, tai galite padaryti tik su išlikimu (), nes merge sukels neteisėtąArgumentException.

D3. Jei nuspręsite rankiniu būdu rūpintis savo identifikatoriais (pvz., Naudojant UUID), tuomet merge operacija atliks tolesnes SELECT užklausas, kad būtų galima ieškoti esamų subjektų su šiuo identifikatoriumi, ir persist nereikia šių užklausų.

D4. Yra atvejų, kai paprasčiausiai nepasitikite kodu, kuris vadina jūsų kodą, ir įsitikinkite, kad duomenys nėra atnaujinami, bet įterpiami, turite naudoti persist .

15
02 дек. Andrei I atsakymas 02 Dec 2013-12-02 17:13 '13, 17:13, 2013-12-02 17:13

Buvau tingusLoading išimtys mano objektas, nes aš bandė gauti prieigą prie tingus įkeltas kolekcija, kuri buvo sesijoje.

Ką norėčiau padaryti atskiru prašymu, ištraukti subjektą iš sesijos ir tada bandyti pasiekti kolekciją mano „jsp“ puslapyje, kuris buvo problemiškas.

Siekiant palengvinti šį procesą, atnaujinau tą patį objektą savo valdiklyje ir perdavė jį savo „jsp“, nors manau, kad dar kartą ją SessionScope sesijoje, kad ji taip pat būtų prieinama, nors „ SessionScope “ nepašalins LazyLoadingException , 2 pavyzdžio pakeitimo:

Toliau dirbau man:

 // scenario 2 MY WAY // tran starts e = new MyEntity(); e = em.merge(e); // re-assign to the same entity "e" //access e from jsp and it will work dandy!! 
8
20 окт. atsakymas pateiktas logixplayer 20 okt. 2010-10-20 19:13 '10, 19:13, 2010-10-20 19:13

Atlikdami atsakymus, yra keletas trūkumų, susijusių su „Cascade“ ir id generacija. Žr. Klausimą

Be to, verta paminėti, kad jūs galite turėti atskiras Cascade anotacijas susijungimui ir taupymui: Cascade.MERGE ir Cascade.PERSIST , kurios bus apdorojamos pagal naudojamą metodą.

Specifikacija - jūsų draugas;)

6
17 июля '14 в 18:41 2014-07-17 18:41 atsakymą įteikė Ioannis Deligiannis , liepos 17 d. 14, 18:41 2014-07-17 18:41

X scenarijus:

Lentelė: Spitter (vienas), lentelė: Spittles (daug) („Spittles“ turi santykius su FK: spitter_id)

Šis scenarijus leidžia išsaugoti: „Spitter“ ir abu spittles, priklausančius tai pačiai „Spitter“.

  Spitter spitter=new Spitter(); Spittle spittle3=new Spittle(); spitter.setUsername("George"); spitter.setPassword("test1234"); spittle3.setSpittle("I love java 2"); spittle3.setSpitter(spitter); dao.addSpittle(spittle3); // <--persist Spittle spittle=new Spittle(); spittle.setSpittle("I love java"); spittle.setSpitter(spitter); dao.saveSpittle(spittle); //<-- merge!! 

Y scenarijus

Tai padės taupyti „Spitter“, išskyrus 2 „Spittles“, tačiau jie nebus susiję su tuo pačiu „Spitter“!

  Spitter spitter=new Spitter(); Spittle spittle3=new Spittle(); spitter.setUsername("George"); spitter.setPassword("test1234"); spittle3.setSpittle("I love java 2"); spittle3.setSpitter(spitter); dao.save(spittle3); // <--merge!! Spittle spittle=new Spittle(); spittle.setSpittle("I love java"); spittle.setSpitter(spitter); dao.saveSpittle(spittle); //<-- merge!! 
5
19 окт. George Papatheodorou atsakymas 19 okt. 2012-10-19 15:32 '12, 15:32 pm 2012-10-19 15:32

Radau šį paaiškinimą iš Hibernate švietimo dokumentų, nes jame yra precedentas:

Susijungimo () naudojimas ir semantika atrodo paini naujiems vartotojams. Pirma, jei nesistengiate naudoti vieno objekto valdytojo įkelto objekto būseną į kitą naują įmonės valdytoją, nereikėtų bendrai naudoti () . Kai kurios programos šio metodo niekada nenaudos.

Paprastai sujungimas () naudojamas sekančiame scenarijuje:

  • Programa įkelia objektą į pirmą įmonės valdytoją.
  • objektas perkeliamas į pateikimo lygį
  • buvo atlikti tam tikri objekto pakeitimai
  • objektas grąžinamas į verslo logikos lygį
  • programa išsaugo šiuos pakeitimus pasitelkdama susijungimą () antrajame subjektų valdytoju

Čia yra tikslus jungimo semantika ():

  • jei yra valdomas egzempliorius, turintis tą patį identifikatorių, kuris šiuo metu yra susietas su atkaklumo kontekstu, nukopijuokite šio objekto būseną į valdomą pavyzdį
  • jei šiuo metu nenaudojate valdomo pavyzdžio, susieto su atkaklumo kontekstu, pabandykite jį atsisiųsti iš duomenų bazės arba sukurti naują tvarkomą pavyzdį
  • grąžintas valdomas pavyzdys
  • šis atvejis nesusijęs su atkaklumo kontekstu, jis išlieka ir paprastai pašalinamas.

Iš: http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/objectstate.html

5
01 сент. Atsakymą pateikė Ray Hulha 01 Sep. 2015-09-01 13:33 '15 , 13:33 2015-09-01 13:33

JPA neabejotinai yra labai paprastas „Java“ platformoje įdiegtų verslo programų srityje. Kaip kūrėjas, kuris turėjo susidoroti su senųjų pupelių objekto J2EE sudėtingumu. Manau, kad JPA įtraukimas į Java EE specifikaciją yra didelis žingsnis į priekį. Vis dėlto, žvelgdamas į JPA detales, aš rasiu dalykus, kurie nėra tokie paprasti. Šiame straipsnyje žiūriu į palyginimą „EntityManagers“ sujungia ir taupo metodus, persidengiantis elgesys gali sukelti painiavą ne tik pradedantiesiems. Be to, siūlau apibendrinti, kad abu metodai laikomi ypatingais bendresnio metodo derinimo atvejais.

Nuolatiniai objektai

Skirtingai nuo sujungimo metodo, išliekantis metodas yra gana paprastas ir intuityvus. Dažniausiai pasitaikančio metodo taikymo scenarijų galima apibendrinti taip:

„Naujas subjekto klasės egzempliorius perduodamas išlikimo metodui. Po šio metodo grąžinimo objektas tvarkomas ir planuojamas įterpti į duomenų bazę. Tai gali įvykti prieš užbaigiant operaciją arba prieš ją, arba kai skalavimo metodas, kai objektas reiškia kitą objektą per santykius, pažymėtus kaskadais PERSIST strategija, ši procedūra taip pat taikoma ir jai.

2019

Возможно, вы пришли за советом о том, когда использовать упорство и когда использовать слияние . Я думаю, что это зависит от ситуации: насколько вероятно, что вам нужно создать новую запись и как трудно получить сохраненные данные.