Oversikt over JPA / Hibernate Cascade Typer

1. Introduksjon

I denne opplæringen vil vi diskutere hva cascading er i JPA / Hibernate. Deretter vil vi dekke de forskjellige kaskadetypene som er tilgjengelige, sammen med deres semantikk.

2. Hva er Cascading?

Enhetsforhold avhenger ofte av eksistensen av en annen enhet - for eksempel PersonAdresse forhold. Uten Person, den Adresse enhet har ingen egen betydning. Når vi sletter Person enhet, vår Adresse enheten skal også bli slettet.

Cascading er måten å oppnå dette på. Når vi utfører noen handlinger på målenheten, vil den samme handlingen bli brukt på den tilknyttede enheten.

2.1. JPA Cascade Type

Alle JPA-spesifikke kaskadeoperasjoner er representert av javax.persistence.CascadeType enum som inneholder oppføringer:

  • ALLE
  • FORTSETTE
  • SLÅ SAMMEN
  • FJERNE
  • FORFRISKE
  • LØSNE

2.2. Hibernate Cascade Type

Dvalemodus støtter tre ekstra kaskadetyper sammen med de som er spesifisert av JPA. Disse dvale-spesifikke kaskadetyper er tilgjengelige i org.hibernate.annotations.CascadeType:

  • GJENSKAPE
  • SAVE_UPDATE
  • LÅSE

3. Forskjellen mellom kaskadetyper

3.1. CascadeType.ALLE

Cascade.ALLforplanter alle operasjoner - inkludert dvalemodus-spesifikke - fra en forelder til en underenhet.

La oss se det i et eksempel:

@Entity offentlig klasse Person {@Id @GeneratedValue (strategi = GenerationType.AUTO) privat int id; privat strengnavn; @OneToMany (mappedBy = "person", cascade = CascadeType.ALL) private Listadresser; }

Legg merke til at i OneToMany foreninger, vi har nevnt kaskadetypen i kommentaren.

La oss nå se den tilknyttede enheten Adresse:

@Entity offentlig klasse Adresse {@Id @GeneratedValue (strategi = GenerationType.AUTO) privat int id; privat String street; privat int husNummer; private String city; privat int zipCode; @ManyToOne (fetch = FetchType.LAZY) privat person person; }

3.2. CascadeType.FORTSETTE

Den vedvarende operasjonen gjør en forbigående forekomst vedvarende. CascadeType FORTSETTE forplanter den vedvarende operasjonen fra en forelder til en underenhet. Når vi lagrer person enhet, den adresse enheten vil også bli lagret.

La oss se testsaken for en vedvarende operasjon:

@Test offentlig ugyldig nårParentSavedThenChildSaved () {Person person = new Person (); Adresse adresse = ny adresse (); address.setPerson (person); person.setAddresses (Arrays.asList (adresse)); session.persist (person); session.flush (); session.clear (); }

Når vi kjører ovennevnte testtilfelle, ser vi følgende SQL:

Dvalemodus: sett inn i Person (navn, id) verdier (?,?) Dvalemodus: sett inn i Adresse (by, husNummer, person_id, gate, zipCode, id) verdier (?,?,?,?,?,?)

3.3. CascadeType.SLÅ SAMMEN

Sammenslåingsoperasjonen kopierer tilstanden til det gitte objektet til det vedvarende objektet med samme identifikator. CascadeType.MERGE overfører sammenslåing fra en forelder til en underordnet enhet.

La oss teste fletteoperasjonen:

@Test offentlig ugyldig nårParentSavedThenMerged () {int addressId; Person person = buildPerson ("devender"); Adresse-adresse = buildAddress (person); person.setAddresses (Arrays.asList (adresse)); session.persist (person); session.flush (); addressId = address.getId (); session.clear (); Adresse savedAddressEntity = session.find (Address.class, addressId); Person savedPersonEntity = savedAddressEntity.getPerson (); savedPersonEntity.setName ("devender kumar"); savedAddressEntity.setHouseNumber (24); session.merge (savedPersonEntity); session.flush (); }

Når vi kjører ovennevnte testtilfelle, genererer fletteoperasjonen følgende SQL:

Dvalemodus: velg adresse0_.id som id1_0_0_, adresse0_.by som by2_0_0_, adresse0_.husNummer som husNum3_0_0_, adresse0_.person_id som person_i6_0_0_, adresse0_.street som gate4_0_0_, adresse0_.zipKode som postnummer = adresse_0 Dvalemodus: velg person0_.id som id1_1_0_, person0_.navn som navn2_1_0_ fra Person person0_ hvor person0_.id =? Dvalemodus: oppdater Adressesett by = ?, husnummer = ?, person_id = ?, gate = ?, zipCode =? hvor id =? Dvalemodus: oppdater personens navn =? hvor id =?

Her kan vi se at fusjonsoperasjonen først laster begge deler adresse og person enheter og oppdaterer deretter begge som et resultat av CascadeType MERGE.

3.4. CascadeType.REMOVE

Som navnet antyder, fjerner fjernoperasjonen raden som tilsvarer enheten fra databasen og også fra den vedvarende konteksten.

CascadeType.REMOVE overfører fjerningsoperasjonen fra foreldre til underenhet.I likhet med JPA-er CascadeType.REMOVE, vi har CascadeType.DELETE, som er spesifikk for dvalemodus. Det er ingen forskjell mellom de to.

Nå er det på tide å teste CascadeType.Remove:

@Test offentlig ugyldig nårParentRemovedThenChildRemoved () {int personId; Person person = buildPerson ("devender"); Adresse-adresse = buildAddress (person); person.setAddresses (Arrays.asList (adresse)); session.persist (person); session.flush (); personId = person.getId (); session.clear (); Person savedPersonEntity = session.find (Person.class, personId); session.remove (savedPersonEntity); session.flush (); }

Når vi kjører ovennevnte testtilfelle, ser vi følgende SQL:

Dvalemodus: slett fra adresse hvor id =? Dvalemodus: slett fra Person der id =?

De adresse assosiert med person ble også fjernet som et resultat av CascadeType FJERN.

3.5. CascadeType.DETACH

Frakoblingsoperasjonen fjerner enheten fra den vedvarende konteksten. Når vi bruker CascaseType.DETACH, den underordnede enheten vil også bli fjernet fra den vedvarende konteksten.

La oss se det i aksjon:

@Test offentlig ugyldig nårParentDetachedThenChildDetached () {Person person = buildPerson ("devender"); Adresse-adresse = buildAddress (person); person.setAddresses (Arrays.asList (adresse)); session.persist (person); session.flush (); assertThat (session.contains (person)). isTrue (); assertThat (session.contains (adresse)). isTrue (); session.detach (person); assertThat (session.contains (person)). isFalse (); assertThat (session.contains (address)). isFalse (); }

Her kan vi se det etter løsrivelse person, ingen person heller ikke adresse eksisterer i den vedvarende sammenhengen.

3.6. CascadeType.LÅSE

Uintuitivt, CascadeType.LOCK kobler enheten og den tilknyttede underenheten til den vedvarende konteksten på nytt.

La oss se testsaken for å forstå CascadeType.LOCK:

@Test offentlig ugyldig nårDetachedAndLockedThenBothReattached () {Person person = buildPerson ("devender"); Adresse-adresse = buildAddress (person); person.setAddresses (Arrays.asList (adresse)); session.persist (person); session.flush (); assertThat (session.contains (person)). isTrue (); assertThat (session.contains (adresse)). isTrue (); session.detach (person); assertThat (session.contains (person)). isFalse (); assertThat (session.contains (address)). isFalse (); session.unwrap (Session.class) .buildLockRequest (new LockOptions (LockMode.NONE)) .lock (person); assertThat (session.contains (person)). isTrue (); assertThat (session.contains (address)). isTrue (); }

Som vi kan se, når du bruker CascadeType.LOCK, festet vi enheten person og tilhørende adresse tilbake til den vedvarende konteksten.

3.7. CascadeType.FORFRISKE

Oppdater operasjoner les verdien av en gitt forekomst på nytt fra databasen. I noen tilfeller kan det hende at vi endrer en forekomst etter at vi har fortsatt i databasen, men senere må vi angre disse endringene.

I den slags scenario kan dette være nyttig. Når vi bruker denne operasjonen med CascadeType FORFRISKEblir den underordnede enheten også lastet inn på nytt fra databasen når den overordnede enheten blir oppdatert.

For bedre forståelse, la oss se en prøvesak for CascadeType.REFRESH:

@Test offentlig ugyldig nårParentRefreshedThenChildRefreshed () {Person person = buildPerson ("devender"); Adresse-adresse = buildAddress (person); person.setAddresses (Arrays.asList (adresse)); session.persist (person); session.flush (); person.setName ("Devender Kumar"); address.setHouseNumber (24); session.refresh (person); assertThat (person.getName ()). isEqualTo ("devender"); assertThat (address.getHouseNumber ()). erEqualTo (23); }

Her gjorde vi noen endringer i de lagrede enhetene person og adresse. Når vi oppdaterer person enhet, den adresse blir også oppdatert.

3.8. CascadeType.REPLICATE

Replikeringsoperasjonen brukes når vi har mer enn én datakilde, og vi vil at dataene skal synkroniseres. Med CascadeType.REPLICATE, en synkroniseringsoperasjon overføres også til underordnede enheter når den utføres på den overordnede enheten.

La oss teste CascadeType.GJENSKAPE:

@Test offentlig ugyldig nårParentReplicatedThenChildReplicated () {Person person = buildPerson ("devender"); person.setId (2); Adresse-adresse = buildAddress (person); address.setId (2); person.setAddresses (Arrays.asList (adresse)); session.unwrap (Session.class) .replicate (person, ReplicationMode.OVERWRITE); session.flush (); assertThat (person.getId ()). er lik (2); assertThat (address.getId ()). erEqualTo (2); }

På grunn av CascadeTypeGJENSKAPE, når vi replikerer person enhet, deretter dens tilknyttede adresse blir også replikert med identifikatoren vi setter.

3.9. CascadeType.SAVE_UPDATE

CascadeType.SAVE_UPDATE forplanter den samme operasjonen til den tilknyttede underenheten. Det er nyttig når vi bruker det Dvalemodus-spesifikke operasjoner som lagre, oppdater, og saveOrUpdate.

La oss se CascadeType.SAVE_UPDATE i aksjon:

@Test offentlig ugyldig nårParentSavedThenChildSaved () {Person person = buildPerson ("devender"); Adresse-adresse = buildAddress (person); person.setAddresses (Arrays.asList (adresse)); session.saveOrUpdate (person); session.flush (); }

På grunn av CascadeType.SAVE_UPDATE, når vi kjører ovennevnte testtilfelle, så kan vi se at person og adresse begge ble reddet. Her er den resulterende SQL:

Dvalemodus: sett inn i person- (navn, id) -verdier (?,?) Dvalemodus: sett inn i adresse (by, husnummer, person_id, gate, zipCode, id) -verdier (?,?,?,?,?,?)

4. Konklusjon

I denne artikkelen diskuterte vi cascading og de forskjellige alternativene for cascade-typer som er tilgjengelige i JPA og Hibernate.

Kildekoden for artikkelen er tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found