Nejprve bych rozlišoval mezi optimistickými a pesimistickými zámky, protože se liší svým základním mechanismem.
Optimistické zamykání je plně řízeno JPA a vyžaduje pouze další sloupec verze v tabulkách DB. Je zcela nezávislý na základním DB engine používaném k ukládání relačních dat.
Na druhou stranu pesimistické zamykání používá zamykací mechanismus poskytovaný podkladovou databází k uzamčení existujících záznamů v tabulkách. JPA potřebuje vědět, jak spouštět tyto zámky a některé databáze je nepodporují nebo jen částečně.
Nyní k seznamu typů zámků:
LockModeType.Optimistic
- Pokud entity specifikují pole verze, jedná se o výchozí hodnotu. U entit bez sloupce verze není zaručeno, že použití tohoto typu zámku bude fungovat v jakékoli implementaci JPA. Tento režim je obvykle ignorován, jak uvádí ObjectDB. Podle mého názoru existuje pouze proto, abyste mohli dynamicky vypočítat režim zámku a předat jej dále, i když by zámek byl nakonec OPTIMISTICKÝ. Není to sice příliš pravděpodobné použití, ale vždy je dobrý návrh API poskytnout možnost odkazovat i na výchozí hodnotu.
-
Příklad:
`LockModeType lockMode = resolveLockMode(); A a = em.find(A.class, 1, lockMode);`
LockModeType.OPTIMISTIC_FORCE_INCREMENT
- Toto je zřídka používaná možnost. Ale mohlo by to být rozumné, pokud chcete uzamknout odkazování na tuto entitu jinou entitou. Jinými slovy, chcete zamknout práci s entitou, i když není upravena, ale jiné entity mohou být ve vztahu k této entitě upraveny.
- Příklad:Máme entitu Book and Shelf. Je možné přidat knihu do police, ale kniha nemá žádný odkaz na svou polici. Je rozumné uzamknout přesun knihy na polici, aby kniha neskončila v jiné polici (kvůli jiné transakci) před ukončením této transakce. K uzamčení této akce nestačí uzamknout aktuální entitu police s knihami, protože kniha ještě nemusí být na poličce. Také nemá smysl zamykat všechny cílové knihovny, protože by se pravděpodobně v různých transakcích lišily. Jediná věc, která dává smysl, je uzamknout samotnou entitu knihy, i když se v našem případě nezmění (neobsahuje odkaz na svou knihovnu).
LockModeType.PESSIMISTIC_READ
- tento režim je podobný režimu
LockModeType.PESSIMISTIC_WRITE
, ale v jedné věci se liší:dokud není na stejné entitě nějakou transakcí nasazen zámek zápisu, nemělo by to blokovat čtení entity. Umožňuje také uzamknout další transakce pomocíLockModeType.PESSIMISTIC_READ
. Rozdíly mezi zámky WRITE a READ jsou dobře vysvětleny zde (ObjectDB) a zde (OpenJPA). Pokud je entita již uzamčena jinou transakcí, jakýkoli pokus o její uzamčení vyvolá výjimku. Toto chování lze upravit tak, aby před vyvoláním výjimky a vrácením transakce nějakou dobu čekalo na uvolnění zámku. Chcete-li to provést, zadejtejavax.persistence.lock.timeout
nápověda s počtem milisekund před vyvoláním výjimky. Existuje několik způsobů, jak toho dosáhnout na několika úrovních, jak je popsáno v tutoriálu Java EE.
LockModeType.PESSIMISTIC_WRITE
- toto je silnější verze
LockModeType.PESSIMISTIC_READ
. KdyžWRITE
zámek je na svém místě, JPA s pomocí databáze zabrání jakékoli jiné transakci čtení entity, nejen zápisu jako uREAD
zámek. - Způsob, jak je to implementováno u poskytovatele JPA ve spolupráci s podkladovou DB, není předepsáno. Ve vašem případě Oracle bych řekl, že Oracle neposkytuje něco blízkého
READ
zámek.SELECT...FOR UPDATE
je ve skutečnosti spíšeWRITE
zámek. Může to být chyba v hibernaci nebo jen rozhodnutí, které namísto implementace vlastního "měkčího"READ
zámek, "tvrdší"WRITE
místo toho se používá zámek. To většinou nenarušuje konzistenci, ale nedrží všechna pravidla sREAD
zámky. Můžete spustit několik jednoduchých testů pomocíREAD
zámky a dlouhotrvající transakce, abyste zjistili, zda je více transakcí schopno získatREAD
zámky na stejnou entitu. To by mělo být možné, ale ne pomocíWRITE
zámky.
- LockModeType.PESSIMISTIC_FORCE_INCREMENT
- toto je další zřídka používaný režim uzamčení. Je to však možnost, kde je potřeba kombinovat
PESSIMISTIC
aOPTIMISTIC
mechanismy. Pomocí prostéhoPESSIMISTIC_WRITE
selže v následujícím scénáři:- transakce A používá optimistické zamykání a čte entitu E
- transakce B získá zámek WRITE na entitě E
- transakce B potvrdí a uvolní zámek E
- transakce A aktualizuje E a odevzdá
- Pokud v kroku 4 není sloupec verze zvýšen o transakci B, nic nebrání A v přepsání změn B. Režim zámku
LockModeType.PESSIMISTIC_FORCE_INCREMENT
vynutí transakci B k aktualizaci čísla verze a způsobí selhání transakce A sOptimisticLockException
, i když B používal pesimistické zamykání.
- LockModeType.NONE
- toto je výchozí hodnota, pokud entity neposkytují pole verze. To znamená, že není povoleno žádné zamykání, konflikty budou vyřešeny na základě maximálního úsilí a nebudou detekovány. Toto je jediný režim uzamčení povolený mimo transakci