Pesimistické zamykanie v JPA

1. Prehľad

Existuje veľa situácií, keď chceme načítať údaje z databázy. Niekedy to chceme uzamknúť pre ďalšie spracovanie, aby nikto iný nemohol prerušiť naše akcie.

Napadajú nás dva mechanizmy riadenia súbežnosti, ktoré nám to umožňujú: nastavenie správnej úrovne izolácie transakcií alebo nastavenie zámku údajov, ktoré v súčasnosti potrebujeme.

Pre databázové pripojenia je definovaná izolácia transakcie. Môžeme ho nakonfigurovať tak, aby zachovával rôzny stupeň zamykania údajov.

Avšak úroveň izolácie sa nastaví po vytvorení spojenia a ovplyvňuje to každé vyhlásenie v tejto súvislosti. Našťastie môžeme použiť pesimistické zamykanie, ktoré využíva databázové mechanizmy na rezervovanie podrobnejšieho výlučného prístupu k údajom.

Môžeme použiť pesimistický zámok, aby sme zabezpečili, že žiadne ďalšie transakcie nemôžu upravovať alebo mazať vyhradené údaje.

Existujú dva typy zámkov, ktoré si môžeme ponechať: exkluzívny zámok a zdieľaný zámok. Keď niekto iný vlastní zdieľaný zámok, mohli sme čítať, ale nie zapisovať údaje. Aby sme mohli vyhradené údaje upraviť alebo vymazať, musíme mať exkluzívny zámok.

Exkluzívne zámky môžeme získať pomocou „VYBERTE ... NA AKTUALIZÁCIU' Vyhlásenia.

2. Zamknite režimy

Špecifikácia JPA definuje tri pesimistické režimy uzamknutia, o ktorých budeme diskutovať:

  • PESSIMISTIC_READ - umožňuje nám získať zdieľaný zámok a zabrániť aktualizácii alebo vymazaniu údajov
  • PESSIMISTIC_WRITE - umožňuje nám získať výlučný zámok a zabrániť čítaniu, aktualizácii alebo vymazaniu údajov
  • PESSIMISTIC_FORCE_INCREMENT - funguje ako PESSIMISTIC_WRITE a dodatočne zvyšuje atribút verzie verzovanej entity

Všetci sú statickými členmi LockModeType triedy a umožniť transakciám získať zámok databázy. Všetky sa zachovajú, kým sa transakcia nezaviaže alebo sa nevráti späť.

Stojí za zmienku, že môžeme získať iba jeden zámok súčasne. Ak je to nemožné a PersistenceException je hodená.

2.1. PESSIMISTIC_READ

Kedykoľvek, keď chceme iba čítať údaje a nestretneme sa so špinavými čítaniami, môžeme použiť PESSIMISTIC_READ (zdieľaný zámok). Nebudeme však môcť robiť žiadne aktualizácie ani mazania.

Niekedy sa stáva, že databáza, ktorú používame, nepodporuje PESSIMISTIC_READ zámok, takže je možné, že získame PESSIMISTIC_WRITE namiesto toho zamkni.

2.2. PESSIMISTIC_WRITE

Akákoľvek transakcia, ktorá vyžaduje získanie zámku údajov a vykonanie zmien v nej, by mala získať PESSIMISTIC_WRITE zámok. Podľa JPA špecifikácia, držanie PESSIMISTIC_WRITE zámok zabráni iným transakciám v načítaní, aktualizácii alebo vymazaní údajov.

Upozorňujeme, že niektoré databázové systémy implementujú riadenie súbežnosti viacerých verzií, ktoré umožňuje čitateľom načítať údaje, ktoré už boli zablokované.

2.3. PESSIMISTIC_FORCE_INCREMENT

Tento zámok funguje podobne ako PESSIMISTIC_WRITE, ale bola zavedená pre spoluprácu s verzovanými entitami - entitami, ktoré majú atribút anotovaný pomocou @ Verzia.

Akékoľvek aktualizácie verzovaných entít by mohli predchádzať získaniu PESSIMISTIC_FORCE_INCREMENT zámok. Získanie tohto zámku povedie k aktualizácii stĺpca verzie.

Je na poskytovateľovi vytrvalosti, aby zistil, či podporuje PESSIMISTIC_FORCE_INCREMENT pre subjekty bez verzie. Ak sa tak nestane, hodí sa Výnimka persistance.

2.4. Výnimky

Je dobré vedieť, ktorá výnimka sa môže vyskytnúť pri práci s pesimistickým zamykaním. JPA špecifikácia poskytuje rôzne typy výnimiek:

  • PessimisticLockException - označuje, že získanie zámku alebo konverzia zdieľaného na výlučný zámok zlyhá a má za následok vrátenie transakcie na úrovni transakcie
  • LockTimeoutException - označuje, že získanie zámku alebo konverzia zdieľaného zámku na exkluzívny časový limit a vedie k vráteniu na úrovni príkazu
  • PersistanceException - naznačuje, že nastal problém s perzistenciou. Výnimka persistance a jeho podtypy, okrem NoResultException, NonUniqueResultException,LockTimeoutExceptiona QueryTimeoutException, označí aktívnu transakciu, ktorá sa má vrátiť späť.

3. Používanie pesimistických zámkov

Existuje niekoľko možných spôsobov, ako nakonfigurovať pesimistický zámok pre jeden záznam alebo skupinu záznamov. Pozrime sa, ako to urobiť v JPA.

3.1. Nájsť

Je to asi najpriamejší spôsob. Stačí prejsť a LockModeType objekt ako parameter do Nájsť metóda:

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

3.2. Dopyt

Ďalej môžeme použiť a Dopyt tiež objekt a zavolajte setLockMode nastavovač s parametrom režimu blokovania:

Dotaz na dotaz = entityManager.createQuery ("od študenta, kde studentId =: studentId"); query.setParameter ("studentId", studentId); query.setLockMode (LockModeType.PESSIMISTIC_WRITE); query.getResultList ()

3.3. Explicitné zamykanie

Je tiež možné ručne uzamknúť výsledky načítané metódou hľadania:

Výsledok študentaStudent = entityManager.find (Student.class, studentId); entityManager.lock (resultStudent, LockModeType.PESSIMISTIC_WRITE);

3.4. Obnoviť

Ak chceme prepísať stav entity na Obnoviť metódou môžeme nastaviť aj zámok:

Výsledok študentaStudent = entityManager.find (Student.class, studentId); entityManager.refresh (resultStudent, LockModeType.PESSIMISTIC_FORCE_INCREMENT);

3.5. NamedQuery

@NamedQuery anotácia nám umožňuje tiež nastaviť režim uzamknutia:

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

4. Zamknite rozsah

Parameter Uzamknúť rozsah definuje, ako riešiť uzamknuté vzťahy uzamknutej entity. Je možné získať zámku iba na jednej entite definovanej v dotaze alebo dodatočne zablokovať jej vzťahy.

Na konfiguráciu rozsahu môžeme použiť PessimisticLockScope enum. Obsahuje dve hodnoty: NORMÁLNE a ROZŠÍRENÝ.

Rozsah môžeme nastaviť odovzdaním parametra ‘javax.persistance.lock.scope‘S PessimisticLockScope hodnota ako argument pre správnu metódu EntityManager, Dopyt, TypedQuery alebo NamedQuery:

Vlastnosti mapy = nový HashMap (); map.put ("javax.persistence.lock.scope", PessimisticLockScope.EXTENDED); entityManager.find (Student.class, 1L, LockModeType.PESSIMISTIC_WRITE, vlastnosti); 

4.1. PessimisticLockScope.NORMÁLNE

Mali by sme vedieť, že PessimisticLockScope.NORMÁLNE je predvolený rozsah. Pomocou tohto rozsahu uzamknutia uzamkneme samotnú entitu. Ak sa použije so spojeným dedičstvom, uzamkne sa ním aj predkov.

Pozrime sa na ukážkový kód s dvoma entitami:

@Entity @Inheritance (strategy = InheritanceType.JOINED) verejná trieda Osoba {@Id private Long id; súkromné ​​meno reťazca; private String priezvisko; // getters and setters} @Entity public class Zamestnanec rozširuje Person {private BigDecimal plate; // zakladatelia a zakladatelia}

Keď chceme získať zámok na Zamestnanec, môžeme pozorovať SQL dopyt, ktorý sa rozprestiera nad týmito dvoma entitami:

VYBERTE t0.ID, t0.DTYPE, t0.LASTNAME, t0.NAME, t1.ID, t1. VÝPLATY OD OSOBY t0, ZAMESTNANEC t1 KDE ((t0.ID =?) AND ((t1.ID = t0.ID) AND (t0.DTYPE =?))) NA AKTUALIZÁCIU

4.2. PessimisticLockScope.EXTENDED

The ROZŠÍRENÝ rozsah pokrýva rovnakú funkcionalitu ako NORMÁLNE. Navyše, je schopný blokovať súvisiace entity v spojovacej tabuľke.

Jednoducho povedané, funguje to s entitami s poznámkami @ElementCollection alebo @Jeden na jedného, @OneToMany atď. s @JoinTable.

Pozrime sa na ukážkový kód s @ElementCollection anotácia:

@Entity public class Customer {@Id private Long customerId; súkromné ​​meno reťazca; private String priezvisko; @ElementCollection @CollectionTable (name = "customer_address") súkromný zoznam addressList; // getters and setters} @Embeddable public class Address {private String country; súkromné ​​mesto String; // zakladatelia a zakladatelia}

Poďme analyzovať niekoľko otázok pri hľadaní Zákazník subjekt:

VYBERTE CUSTOMERID, PRIEZVISKO, NÁZOV OD ZÁKAZNÍKA KDE (CUSTOMERID =?) NA AKTUALIZÁCIU VYBERTE MESTO, KRAJINU, Customer_CUSTOMERID FROM customer_address WHERE (Customer_CUSTOMERID =?) NA AKTUALIZÁCIU

Vidíme, že existujú dva ‘AKTUALIZÁCIA„Dotazy, ktoré uzamknú riadok v tabuľke zákazníkov aj riadok v spojovacej tabuľke.

Ďalšou zaujímavou skutočnosťou, ktorú by sme si mali uvedomiť, je, že nie všetci poskytovatelia perzistencie podporujú rozsahy uzamknutia.

5. Nastavenie časového limitu zámku

Okrem nastavenia rozsahov uzamknutia môžeme upraviť ďalší parameter uzamknutia - časový limit. Hodnota časového limitu je počet milisekúnd, po ktorý chceme počkať na získanie zámku, kým LockTimeoutException vyskytuje.

Hodnotu časového limitu môžeme zmeniť podobne ako uzamknuté rozsahy pomocou vlastnosti ‘javax.persistence.lock.timeout ' so správnym počtom milisekúnd.

Je tiež možné určiť uzamknutie „bez čakania“ zmenou hodnoty časového limitu na nulu. Mali by sme však mať na pamäti, že existujú aj ovládače databázy, ktoré nepodporujú nastavenie hodnoty časového limitu týmto spôsobom.

Vlastnosti mapy = nový HashMap (); map.put ("javax.persistence.lock.timeout", 1 000 L); entityManager.find (Student.class, 1L, LockModeType.PESSIMISTIC_READ, vlastnosti);

6. Záver

Keď nastavenie správnej úrovne izolácie nestačí na zvládnutie súbežných transakcií, JPA nám poskytuje pesimistické blokovanie. Umožňuje nám to izolovať a organizovať rôzne transakcie, aby nemali prístup k rovnakému prostriedku v rovnakom čase.

Aby sme to dosiahli, môžeme si vybrať medzi diskutovanými typmi zámkov a následne upraviť také parametre, ako sú ich rozsahy alebo časové limity.

Na druhej strane by sme si mali pamätať, že porozumenie databázovým zámkom je rovnako dôležité ako porozumenie mechanizmom základných databázových systémov. Je tiež dôležité mať na pamäti, že správanie pesimistických zámkov závisí od poskytovateľa perzistencie, s ktorým pracujeme.

Nakoniec je zdrojový kód tohto tutoriálu k dispozícii na serveri GitHub pre režim dlhodobého spánku a pre EclipseLink.


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