Pesimistično zaključavanje u JPA

1. Pregled

Puno je situacija kada želimo dohvatiti podatke iz baze podataka. Ponekad ga želimo zaključati za daljnju obradu kako nitko drugi ne bi mogao prekinuti naše postupke.

Možemo smisliti dva mehanizma za kontrolu paralelnosti koji nam to omogućuju: postavljanje odgovarajuće razine izolacije transakcije ili postavljanje zaključavanja podataka koji su nam potrebni u ovom trenutku.

Izolacija transakcije definirana je za veze s bazom podataka. Možemo ga konfigurirati da zadrži različiti stupanj zaključavanja podataka.

Međutim, razina izolacije postavlja se nakon uspostavljanja veze i utječe na svaku izjavu unutar te veze. Srećom, možemo koristiti pesimistično zaključavanje koje koristi mehanizme baze podataka za rezerviranje granuliranijeg ekskluzivnog pristupa podacima.

Pesimističnom bravom možemo se pobrinuti da niti jedna druga transakcija ne može izmijeniti ili izbrisati rezervirane podatke.

Dvije su brave koje možemo zadržati: ekskluzivna brava i zajednička brava. Mogli bismo čitati, ali ne i upisivati ​​podatke kada netko drugi drži zajedničku bravu. Da bismo mogli izmijeniti ili izbrisati rezervirane podatke, moramo imati ekskluzivnu blokadu.

Ekskluzivne brave možemo nabaviti pomoću 'ODABERITE… ZA AŽURIRANJE‘Izjave.

2. Načini zaključavanja

JPA specifikacija definira tri pesimistična načina zaključavanja o kojima ćemo razgovarati:

  • PESSIMISTIC_READ - omogućuje nam dobivanje zajedničkog zaključavanja i sprječavanje ažuriranja ili brisanja podataka
  • PESSIMISTIC_WRITE - omogućuje nam da dobijemo ekskluzivnu bravu i spriječimo čitanje, ažuriranje ili brisanje podataka
  • PESSIMISTIC_FORCE_INCREMENT - djeluje poput PESSIMISTIC_WRITE a dodatno povećava atribut verzije verzioniranog entiteta

Svi su oni statični članovi LockModeType klase i dopuštaju transakcijama dobivanje zaključavanja baze podataka. Svi se zadržavaju dok se transakcija ne obveže ili povuče.

Vrijedno je primijetiti da istodobno možemo dobiti samo jednu bravu. Ako je to nemoguće a PerzistentnostIznimka baca se.

2.1. PESSIMISTIC_READ

Kad god želimo samo čitati podatke i ne susrećemo se s prljavim čitanjem, mogli bismo koristiti PESSIMISTIC_READ (zajednička brava). Ipak nećemo biti u mogućnosti ažurirati ili izbrisati.

Ponekad se dogodi da baza podataka koju koristimo ne podržava PESSIMISTIC_READ brava, pa je moguće da dobijemo PESSIMISTIC_WRITE umjesto toga zaključaj.

2.2. PESSIMISTIC_WRITE

Svaka transakcija koja treba steći zaključavanje podataka i unijeti promjene u njih treba dobiti PESSIMISTIC_WRITE zaključati. Prema JPA specifikacija, držanje PESSIMISTIC_WRITE lock onemogućit će čitanje, ažuriranje ili brisanje drugih transakcija.

Imajte na umu da neki sustavi baza podataka implementiraju kontrolu nad istodobnošću više verzija koja čitateljima omogućuje dohvaćanje podataka koji su već blokirani.

2.3. PESSIMISTIC_FORCE_INCREMENT

Ova brava radi slično kao PESSIMISTIC_WRITE, ali uveden je za suradnju s verzijama entiteta - entitetima koji imaju atribut označen s @Verzija.

Svakom ažuriranju verzijskih entiteta može prethoditi dobivanje PESSIMISTIC_FORCE_INCREMENT zaključati. Stjecanje tog zaključavanja rezultira ažuriranjem stupca verzije.

Dobavljač upornosti mora utvrditi podržava li to PESSIMISTIC_FORCE_INCREMENT za neverzijske entitete ili ne. Ako ne, baca PersistanceException.

2.4. Iznimke

Dobro je znati koja se iznimka može dogoditi tijekom rada s pesimističnim zaključavanjem. JPA specifikacija pruža različite vrste iznimaka:

  • PessimisticLockException - označava da dobivanje zaključavanja ili pretvaranje zajedničkog u ekskluzivno zaključavanje ne uspije i rezultira povratom na razini transakcije
  • LockTimeoutException - označava da dobivanje zaključavanja ili pretvaranje zajedničke brave u ekskluzivna vremenska ograničenja rezultira vraćanjem na razinu izjave
  • PersistanceException - ukazuje na to da se pojavio problem trajnosti. PersistanceException i njegove podvrste, osim NoResultException, NonUniqueResultException,LockTimeoutException, i QueryTimeoutException, označava aktivnu transakciju koja će se vratiti.

3. Korištenje pesimističkih brava

Postoji nekoliko mogućih načina za konfiguriranje pesimističnog zaključavanja na jednom zapisu ili grupi zapisa. Pogledajmo kako to učiniti u JPA.

3.1. Pronaći

To je vjerojatno najjednostavniji način. Dovoljno je proći a LockModeType objekt kao parametar za pronaći metoda:

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

3.2. Upit

Uz to možemo koristiti i Upit objekt također nazovite setLockMode postavljač s načinom zaključavanja kao parametrom:

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

3.3. Eksplicitno zaključavanje

Također je moguće ručno zaključati rezultate dohvaćene metodom pronalaženja:

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

3.4. Osvježiti

Ako želimo prepisati stanje entiteta pomoću osvježiti metodom, možemo postaviti i zaključavanje:

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

3.5. NamedQuery

@NamedQuery napomena nam omogućuje da postavimo i način zaključavanja:

@NamedQuery (name = "lockStudent", query = "SELECT s FROM Student s WHERE s.id LIKE: studentId", lockMode = PESSIMISTIC_READ)

4. Opseg zaključavanja

Parametar opsega zaključavanja definira kako postupati s odnosima zaključavanja zaključanog entiteta. Moguće je dobiti zaključavanje samo za jedan entitet definiran u upitu ili dodatno blokirati njegove veze.

Da bismo konfigurirali opseg koji možemo koristiti PessimisticLockScope nabrajanje. Sadrži dvije vrijednosti: NORMALAN i PROŠIRENO.

Opseg možemo postaviti dodavanjem parametra ‘javax.persistance.lock.scope‘Sa PessimisticLockScope vrijednost kao argument pravilnoj metodi EntityManager, Upit, TypedQuery ili NamedQuery:

Svojstva mape = novi HashMap (); map.put ("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED); entityManager.find (Student.class, 1L, LockModeType.PESSIMISTIC_WRITE, svojstva); 

4.1. PessimisticLockScope.NORMALNO

Trebali bismo znati da PessimisticLockScope.NORMALNO zadani je opseg. Ovim opsegom zaključavanja zaključavamo sam entitet. Kada se koristi s pridruženim nasljedstvom, zaključava i pretke.

Pogledajmo primjer uzorka s dva entiteta:

@Entity @Inheritance (strategy = InheritanceType.JOINED) javna klasa Osoba {@Id private Long id; privatni naziv niza; private String lastName; // getters and setters} @Entity public class Employee extends Person {private BigDecimal pay; // geteri i postavljači}

Kad želimo dobiti bravu na Zaposlenik, možemo promatrati SQL upit koji se proteže na ta dva entiteta:

ODABERITE t0.ID, t0.DTYPE, t0.LASTNAME, t0.NAME, t1.ID, t1.PLAĆA OD OSOBE t0, ZAPOSLENIKA t1 GDJE ((t0.ID =?) I ((t1.ID = t0.ID) I (t0.DTYPE =?))) ZA AŽURIRANJE

4.2. PessimisticLockScope.PRODUŽEN

The PROŠIRENO opseg pokriva istu funkcionalnost kao i NORMALAN. U Dodatku, u mogućnosti je blokirati povezane entitete u tablici pridruživanja.

Jednostavno rečeno, radi s entitetima označenim s @ElementCollection ili @Jedan na jedan, @OneToMany itd. sa @JoinTable.

Pogledajmo uzorak koda s @ElementCollection napomena:

@ Entity public class Customer {@Id private Long customerId; privatni naziv niza; private String lastName; @ElementCollection @CollectionTable (name = "customer_address") privatni popis addressList; // getteri i postavljači} @Embedvable javna klasa Adresa {private String country; privatni gudački grad; // geteri i postavljači}

Analizirajmo neke upite prilikom pretraživanja Kupac entitet:

ODABERITE KORISNIČKO, PREZIME, IME OD KUPCA GDJE (KORISNIČKO =?) ZA AŽURIRANJE ODABIRITE GRAD, ZEMLJU, Customer_CUSTOMERID IZ korisničke adrese GDJE (Customer_CUSTOMERID =?) ZA AŽURIRANJE

Možemo vidjeti da postoje dvijeNA AŽURIRANJE‘Upiti koji zaključavaju red u tablici kupaca kao i red u tablici spajanja.

Još jedna zanimljiva činjenica koje bismo trebali biti svjesni je da ne podržavaju svi pružatelji ustrajnosti opseg zaključavanja.

5. Postavljanje vremenskog ograničenja zaključavanja

Osim postavljanja opsega zaključavanja, možemo prilagoditi još jedan parametar zaključavanja - vremensko ograničenje. Vrijednost vremenskog ograničenja je broj milisekundi na koje želimo pričekati dobivanje zaključavanja dok se LockTimeoutException javlja se.

Vrijednost vremenskog ograničenja možemo promijeniti slično kao i opsezi zaključavanja, koristeći svojstvo ‘javax.persistence.lock.timeout ' s odgovarajućim brojem milisekundi.

Također je moguće odrediti zaključavanje 'bez čekanja' promjenom vrijednosti vremenskog ograničenja na nulu. Međutim, trebali bismo imati na umu da postoje pokretački programi baze podataka koji ne podržavaju postavljanje vrijednosti vremenskog ograničenja na ovaj način.

Svojstva karte = novi HashMap (); map.put ("javax.persistence.lock.timeout", 1000L); entityManager.find (Student.class, 1L, LockModeType.PESSIMISTIC_READ, svojstva);

6. Zaključak

Kada postavljanje odgovarajuće razine izolacije nije dovoljno za suočavanje s istodobnim transakcijama, JPA nam daje pesimistično zaključavanje. Omogućuje nam izoliranje i organiziranje različitih transakcija tako da one istodobno ne pristupaju istim resursima.

Da bismo to postigli, možemo birati između raspravljanih vrsta brava i posljedično modificirati takve parametre kao što su njihovi opsezi ili vremenska ograničenja.

S druge strane, trebali bismo imati na umu da je razumijevanje zaključavanja baze podataka jednako važno kao i razumijevanje mehanizama temeljnih sustava baza podataka. Također je važno imati na umu da ponašanje pesimističnih brava ovisi o pružatelju upornosti s kojim radimo.

Napokon, izvorni kod ovog vodiča dostupan je na GitHub-u za hibernaciju i za EclipseLink.


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