Optimistično zaključavanje u JPA

1. Uvod

Što se tiče poslovnih aplikacija, presudno je pravilno upravljati istodobnim pristupom bazi podataka. To znači da bismo trebali biti u mogućnosti obrađivati ​​više transakcija na učinkovit i najvažniji način, otporan na pogreške.

Štoviše, moramo osigurati da podaci ostanu dosljedni između istodobnih čitanja i ažuriranja.

Da bismo to postigli, možemo se poslužiti optimističnim mehanizmom zaključavanja koji pruža Java Persistent API. To dovodi do toga da višestruka ažuriranja izvršena na istim podacima istovremeno ne ometaju jedno drugo.

2. Razumijevanje optimističnog zaključavanja

Da bismo koristili optimistično zaključavanje, moramo imati entitet uključujući i vlasništvo sa @Verzija bilješka. Dok ga koristi, svaka transakcija koja čita podatke drži vrijednost svojstva verzije.

Prije nego što transakcija želi izvršiti ažuriranje, ponovno provjerava svojstvo verzije.

Ako se vrijednost u međuvremenu promijenila, OptimisticLockException baca se. Inače, transakcija zahtijeva ažuriranje i povećava svojstvo vrijednosti vrijednosti.

3. Pesimistično zaključavanje nasuprot optimističnom zaključavanju

Dobro je znati da nam za razliku od optimističnog zaključavanja JPA daje pesimistično zaključavanje. To je još jedan mehanizam za rukovanje istodobnim pristupom podacima.

Pesimistično zaključavanje pokrivamo u jednom od naših prethodnih članaka - Pesimističko zaključavanje u JPA. Otkrijmo u čemu je razlika i kako možemo imati koristi od svake vrste zaključavanja.

Kao što smo već rekli, optimistično zaključavanje temelji se na otkrivanju promjena na entitetima provjerom njihovog atributa verzije. Ako se dogodi istodobno ažuriranje, OptmisticLockException javlja se. Nakon toga možemo pokušati ažurirati podatke.

Možemo zamisliti da je ovaj mehanizam pogodan za aplikacije koje mnogo više čitaju nego ažuriraju ili brišu. Štoviše, korisno je u situacijama kada se entiteti moraju odvojiti neko vrijeme i brave se ne mogu držati.

Naprotiv, pesimistički mehanizam zaključavanja uključuje zaključavanje entiteta na razini baze podataka.

Svaka transakcija može dobiti zaključavanje podataka. Sve dok drži zaključavanje, nijedna transakcija ne može čitati, brisati ili ažurirati zaključane podatke. Možemo pretpostaviti da korištenje pesimističnog zaključavanja može rezultirati zastojima. Međutim, osigurava veći integritet podataka od optimističnog zaključavanja.

4. Atributi verzije

Atributi verzije svojstva su s @Verzija bilješka. Neophodni su za omogućavanje optimističnog zaključavanja. Pogledajmo primjer klase entiteta:

@ Entity javni razred student {@Id private Long id; privatni naziv niza; private String lastName; @Version privatna cjelovita verzija; // geteri i postavljači}

Postoji nekoliko pravila kojih bismo se trebali pridržavati prilikom deklariranja atributa verzije:

  • svaka klasa entiteta mora imati samo jedan atribut verzije
  • mora se smjestiti u primarnu tablicu za entitet preslikan u nekoliko tablica
  • Tip atributa verzije mora biti jedan od sljedećih: int, Cijeli broj, dugo, Dugo, kratak, Kratak, java.sql.Timestamp

Morali bismo znati da vrijednost atributa verzije možemo dohvatiti putem entiteta, ali ga ne smijemo ažurirati ili povećavati. To može učiniti samo pružatelj ustrajnosti, tako da podaci ostaju dosljedni.

Vrijedno je primijetiti da pružatelji trajnosti mogu podržati optimistično zaključavanje za entitete koji nemaju atribute verzije. Ipak, dobra je ideja uvijek raditi atribute verzije kada radite s optimističnim zaključavanjem.

Ako pokušamo zaključati entitet koji ne sadrži takav atribut, a pružatelj trajnosti ga ne podržava, rezultirat će PersitenceException.

5. Načini zaključavanja

JPA nam nudi dva različita optimistična načina zaključavanja (i dva zamjenska imena):

  • OPTIMISTIČNA - dobiva optimističnu blokadu čitanja za sve entitete koji sadrže atribut verzije
  • OPTIMISTIC_FORCE_INCREMENT - dobiva optimističnu bravu isto kao i OPTIMISTIČNA i dodatno povećava vrijednost atributa verzije
  • ČITATI - to je sinonim za OPTIMISTIČNA
  • PISATI - to je sinonim za OPTIMISTIC_FORCE_INCREMENT

Sve gore navedene vrste možemo pronaći u LockModeType razred.

5.1. OPTIMISTIČNA (ČITATI)

Kao što već znamo, OPTIMISTIČNA i ČITATI načini zaključavanja su sinonimi. Međutim, JPA specifikacija preporučuje nam upotrebu OPTIMISTIČNA u novim aplikacijama.

Kad god zatražimo OPTIMISTIČNA način zaključavanja, pružatelj trajnosti spriječit će naše podatke od prljavih čitanja kao i od neponovljivih čitanja.

Pojednostavljeno, trebao bi osigurati da bilo koja transakcija ne izvrši bilo kakvu izmjenu podataka koje druga transakcija:

  • je ažurirao ili izbrisao, ali nije počinio
  • je u međuvremenu uspješno ažurirao ili izbrisao

5.2. OPTIMISTIC_INCREMENT (PISATI)

Isto kao i prije, OPTIMISTIC_INCREMENT i PISATI su sinonimi, ali prvi je poželjniji.

OPTIMISTIC_INCREMENT mora ispunjavati iste uvjete kao i OPTIMISTIČNA način zaključavanja. Uz to, povećava vrijednost atributa verzije. Međutim, nije precizirano treba li to učiniti odmah ili se može odgoditi do urezivanja ili ispiranja.

Vrijedno je znati da pružatelj usluga ustrajnosti smije to pružiti OPTIMISTIC_INCREMENT funkcionalnost kada OPTIMISTIČNA potreban je način zaključavanja.

6. Korištenje optimističnog zaključavanja

Trebali bismo imati na umu da je za verzijske entitete prema zadanim postavkama dostupno optimistično zaključavanje. Ipak, postoji nekoliko načina da se to izričito zatraži.

6.1. Pronaći

Da bismo zatražili optimistično zaključavanje, možemo proslijediti odgovarajuće LockModeType kao argument za pronalaženje metode EntityManager:

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

6.2. Upit

Drugi način omogućavanja zaključavanja je upotreba setLockMode metoda Upit objekt:

Upit upita = entityManager.createQuery ("od Student gdje id =: id"); query.setParameter ("id", studentId); query.setLockMode (LockModeType.OPTIMISTIC_INCREMENT); query.getResultList ()

6.3. Eksplicitno zaključavanje

Zaključavanje možemo postaviti pozivom EnitityManager's zaključati metoda:

Student student = entityManager.find (Student.class, id); entityManager.lock (student, LockModeType.OPTIMISTIC);

6.4. Osvježiti

Možemo nazvati osvježiti metoda na isti način kao i prethodna metoda:

Student student = entityManager.find (Student.class, id); entityManager.refresh (student, LockModeType.READ);

6.5. NamedQuery

Posljednja opcija je upotreba @NamedQuery s lockMode svojstvo:

@NamedQuery (name = "optimisticLock", query = "SELECT s FROM student s WHERE s.id LIKE: id", lockMode = WRITE)

7. OptimisticLockException

Kada pružatelj trajnosti otkrije optimistične sukobe zaključavanja na entitetima, on baca OptimisticLockException. Morali bismo biti svjesni da je zbog iznimke aktivna transakcija uvijek označena za vraćanje.

Dobro je znati kako možemo reagirati OptimisticLockException. Prikladno, ova iznimka sadrži referencu na sukobljeni entitet. Međutim, nije obvezno da ga pružatelj ustrajnosti isporučuje u svakoj situaciji. Ne postoji jamstvo da će objekt biti dostupan.

Ipak, postoji preporučeni način rješavanja opisane iznimke. Morali bismo ponovno doći do entiteta ponovnim učitavanjem ili osvježavanjem. Po mogućnosti u novoj transakciji. Nakon toga možemo ga pokušati još jednom ažurirati.

8. Zaključak

U ovom smo uputstvu upoznali alat koji nam može pomoći u organiziranju istodobnih transakcija. Optimistično zaključavanje koristi atribute verzije uključene u entitete za kontrolu istodobnih modifikacija na njima.

Stoga osigurava da se ažuriranja ili brisanja neće prebrisati ili tiho izgubiti. Suprotno pesimističnom zaključavanju, on ne zaključava entitete na razini baze podataka i shodno tome, nije ranjiv na DB mrtve točke.

Saznali smo da je optimistično zaključavanje prema verzijama entiteta omogućeno prema zadanim postavkama. Međutim, postoji nekoliko načina da se to izričito zahtijeva upotrebom različitih vrsta načina zaključavanja.

Još jedna činjenica koju bismo trebali zapamtiti je da bismo svaki put kada postoje oprečna ažuriranja entiteta trebali očekivati OptimisticLockException.

Napokon, izvorni kod ovog vodiča dostupan je na GitHub-u.