Pessimistisk låsing i JPA

1. Oversikt

Det er mange situasjoner når vi ønsker å hente data fra en database. Noen ganger ønsker vi å låse den for oss selv for videre behandling, slik at ingen andre kan forstyrre våre handlinger.

Vi kan tenke på to samtidige kontrollmekanismer som lar oss gjøre det: sette riktig transaksjonsisolasjonsnivå eller sette en lås på data vi trenger for øyeblikket.

Transaksjonsisolasjonen er definert for databaseforbindelser. Vi kan konfigurere den til å beholde den forskjellige graden av låsedata.

Derimot, isolasjonsnivået er angitt når forbindelsen er opprettet og det påvirker alle utsagn i den forbindelsen. Heldigvis kan vi bruke pessimistisk låsing som bruker databasemekanismer for å reservere mer detaljert eksklusiv tilgang til dataene.

Vi kan bruke en pessimistisk lås for å sikre at ingen andre transaksjoner kan endre eller slette reserverte data.

Det er to typer låser vi kan beholde: en eksklusiv lås og en delt lås. Vi kunne lese, men ikke skrive inn data når noen andre har en delt lås. For å endre eller slette de reserverte dataene, må vi ha en eksklusiv lås.

Vi kan anskaffe eksklusive låser ved hjelp av ‘VELG… FOR OPPDATERING‘Uttalelser.

2. Lås modus

JPA-spesifikasjon definerer tre pessimistiske låsemoduser som vi skal diskutere:

  • PESSIMISTIC_READ - lar oss få en delt lås og forhindre at data blir oppdatert eller slettet
  • PESSIMISTIC_WRITE - lar oss få en eksklusiv lås og forhindre at data blir lest, oppdatert eller slettet
  • PESSIMISTIC_FORCE_INCREMENT - fungerer som PESSIMISTIC_WRITE og det øker i tillegg et versjonsattributt til en versjonert enhet

Alle er statiske medlemmer av LockModeType klasse og tillate transaksjoner å få en databaselås. De beholdes alle til transaksjonen forplikter eller ruller tilbake.

Det er verdt å merke seg at vi bare kan få en lås om gangen. Hvis det er umulig a PersistenceException blir kastet.

2.1. PESSIMISTIC_READ

Når vi bare vil lese data og ikke støte på skitne lesninger, kan vi bruke det PESSIMISTIC_READ (delt lås). Vi kan ikke gjøre noen oppdateringer eller slettinger.

Noen ganger hender det at databasen vi bruker ikke støtter PESSIMISTIC_READ lås, så det er mulig at vi får tak i PESSIMISTIC_WRITE låse i stedet.

2.2. PESSIMISTIC_WRITE

Enhver transaksjon som må skaffe seg en lås på data og gjøre endringer i den, skal skaffe seg PESSIMISTIC_WRITE låse. Ifølge JPA spesifikasjon, holder PESSIMISTIC_WRITE lock vil forhindre at andre transaksjoner leser, oppdaterer eller sletter dataene.

Vær oppmerksom på at noen databasesystemer implementerer flervisjons samtidighetskontroll som lar leserne hente data som allerede er blokkert.

2.3. PESSIMISTIC_FORCE_INCREMENT

Denne låsen fungerer på samme måte som PESSIMISTIC_WRITE, men det ble introdusert for å samarbeide med versjonerte enheter - enheter som har et attributt kommentert med @Versjon.

Eventuelle oppdateringer av versjonerte enheter kan gå foran innhenting av PESSIMISTIC_FORCE_INCREMENT låse. Å anskaffe den låsen resulterer i oppdatering av versjonskolonnen.

Det er opp til en utholdenhetsleverandør å avgjøre om den støtter PESSIMISTIC_FORCE_INCREMENT for uverserte enheter eller ikke. Hvis den ikke gjør det, kaster den Persistens unntak.

2.4. Unntak

Det er godt å vite hvilket unntak som kan oppstå når du arbeider med pessimistisk låsing. JPA spesifikasjonen gir forskjellige typer unntak:

  • PessimisticLockException - indikerer at å skaffe en lås eller konvertere en delt til eksklusiv lås mislykkes og resulterer i tilbakeføring på transaksjonsnivå
  • LockTimeoutException - indikerer at å skaffe en lås eller konvertere en delt lås til eksklusiv tidsavbrudd og resulterer i en tilbakestilling på uttalelsesnivå
  • PersistanceException - indikerer at det oppstod et vedvarende problem. Persistens unntak og dens undertyper, bortsett fra NoResultException, NonUniqueResultException,LockTimeoutException, og QueryTimeoutException, markerer den aktive transaksjonen som skal rulles tilbake.

3. Bruke pessimistiske låser

Det er noen mulige måter å konfigurere en pessimistisk lås på en enkelt plate eller gruppe av poster. La oss se hvordan du gjør det i JPA.

3.1. Finne

Det er sannsynligvis den enkleste måten. Det er nok å passere en LockModeType objekt som parameter til finne metode:

entityManager.find (Student.class, studentId, LockModeType.PESSIMISTIC_READ);

3.2. Spørsmål

I tillegg kan vi bruke en Spørsmål objekt også og ring setLockMode setter med låsemodus som parameter:

Query query = entityManager.createQuery ("fra Student hvor studentId =: studentId"); query.setParameter ("studentId", studentId); query.setLockMode (LockModeType.PESSIMISTIC_WRITE); query.getResultList ()

3.3. Eksplisitt låsing

Det er også mulig å låse resultatene hentet ved å finne metoden manuelt:

StudentresultatStudent = entityManager.find (Student.class, studentId); entityManager.lock (resultStudent, LockModeType.PESSIMISTIC_WRITE);

3.4. Forfriske

Hvis vi vil overskrive enhetens tilstand av forfriske metode, kan vi også stille en lås:

StudentresultatStudent = entityManager.find (Student.class, studentId); entityManager.refresh (resultStudent, LockModeType.PESSIMISTIC_FORCE_INCREMENT);

3.5. NamedQuery

@NamedQuery merknader lar oss også sette en låsemodus:

@NamedQuery (name = "lockStudent", spørring = "SELECT s FRA Student s WHERE s.id LIKE: studentId", lockMode = PESSIMISTIC_READ)

4. Lås omfang

Lås omfangsparameter definerer hvordan du skal håndtere låseforhold for den låste enheten. Det er mulig å få en lås bare på en enkelt enhet definert i et spørsmål eller i tillegg blokkere dens relasjoner.

For å konfigurere omfanget vi kan bruke PessimisticLockScope enum. Den inneholder to verdier: VANLIG og FORLENGET.

Vi kan angi omfanget ved å sende en parameter ‘javax.persistance.lock.scope‘Med PessimisticLockScope verdi som argument for riktig metode for EntityManager, Spørsmål, TypedQuery eller NamedQuery:

Kartegenskaper = nytt HashMap (); map.put ("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED); entityManager.find (Student.class, 1L, LockModeType.PESSIMISTIC_WRITE, egenskaper); 

4.1. PessimisticLockScope.NORMAL

Vi burde vite at PessimisticLockScope.NORMAL er standardområdet. Med dette låsingsomfanget låser vi selve enheten. Når den brukes med sammenføyd arv, låser den også forfedrene.

La oss se på eksempelkoden med to enheter:

@Entity @ Arv (strategi = InheritanceType.JOINED) offentlig klasse Person {@Id privat Lang id; privat strengnavn; privat streng etternavn; // getters and setters} @Entity offentlig klasse Ansatt utvider Person {privat BigDecimal lønn; // getters og setters}

Når vi ønsker å få en lås på Ansatt, kan vi observere SQL spørring som spenner over de to enhetene:

VELG t0.ID, t0.DTYPE, t0.LASTNAME, t0.NAME, t1.ID, t1.SALAR FRA PERSON t0, MEDARBEIDER t1 HVOR ((t0.ID =?) OG ((t1.ID = t0.ID) OG (t0.DTYPE =?))) FOR OPPDATERING

4.2. PessimisticLockScope.UTVIDET

De FORLENGET omfang dekker samme funksjonalitet som VANLIG. I tillegg, det er i stand til å blokkere relaterte enheter i en sammenføyningstabell.

Enkelt sagt, det fungerer med enheter kommentert med @ElementCollection eller @OneToOne, @OneToMany etc. med @JoinTable.

La oss se på eksempelkoden med @ElementCollection kommentar:

@Entity offentlig klasse kunde {@Id privat Lang kundeId; privat strengnavn; privat streng etternavn; @ElementCollection @CollectionTable (name = "customer_address") privat liste adresseliste; // getters and setters} @ Embeddable public class Address {private String country; private String city; // getters og setters}

La oss analysere noen spørsmål når vi søker etter Kunde enhet:

VELG KUNDEMIDDEL, EFTERNAVN, NAVN FRA KUNDEN HVOR (KUNDEMIDD =?) FOR OPPDATERING VELG BY, LAND, Kunde_KUNDEMIDD FRA kunde_adresse HVOR (Kunde_KUNDEID =?) FOR OPPDATERING

Vi kan se at det er to ‘FOR OPPDATERING‘Spørsmål som låser en rad i kundetabellen så vel som en rad i sammenføyningstabellen.

Et annet interessant faktum vi bør være klar over er at ikke alle utholdenhetsleverandører støtter låsekoder.

5. Stille inn tidsavbrudd for lås

I tillegg til å sette låsekopier, kan vi justere en annen låseparameter - timeout. Tidsavbruddverdien er antall millisekunder som vi ønsker å vente på å få en lås til LockTimeoutException inntreffer.

Vi kan endre verdien på tidsavbrudd på samme måte som låseomfang, ved å bruke egenskapen ‘javax.persistence.lock.timeout ' med riktig antall millisekunder.

Det er også mulig å spesifisere "nei vent" -låsing ved å endre timeout-verdien til null. Vi bør imidlertid huske på at det finnes databasedrivere som støtter ikke å sette en tidsavbruddsverdi på denne måten.

Kartegenskaper = nytt HashMap (); map.put ("javax.persistence.lock.timeout", 1000L); entityManager.find (Student.class, 1L, LockModeType.PESSIMISTIC_READ, egenskaper);

6. Konklusjon

Når det ikke er nok å sette riktig isolasjonsnivå for å takle samtidige transaksjoner, gir JPA oss pessimistisk låsing. Det gjør det mulig for oss å isolere og organisere forskjellige transaksjoner, slik at de ikke får tilgang til samme ressurs samtidig.

For å oppnå det kan vi velge mellom diskuterte typer låser og følgelig endre parametere som omfang eller tidsavbrudd.

På den annen side bør vi huske at forståelse av databaselåser er like viktig som å forstå mekanismene til underliggende databasesystemer. Det er også viktig å ha i bakhodet at oppførselen til pessimistiske låser avhenger av utholdenhetsleverandøren vi jobber med.

Til slutt er kildekoden til denne opplæringen tilgjengelig på GitHub for dvalemodus og for EclipseLink.


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