Najpierw rozróżniłbym blokady optymistyczne i pesymistyczne, ponieważ różnią się one mechanizmem leżącym u ich podstaw.
Blokowanie optymistyczne jest w pełni kontrolowane przez JPA i wymaga jedynie dodatkowej kolumny wersji w tabelach DB. Jest całkowicie niezależny od bazowego silnika bazy danych używanego do przechowywania danych relacyjnych.
Z drugiej strony, blokowanie pesymistyczne wykorzystuje mechanizm blokowania zapewniany przez podstawową bazę danych do blokowania istniejących rekordów w tabelach. JPA musi wiedzieć, jak uruchomić te blokady, a niektóre bazy danych nie obsługują ich lub tylko częściowo.
Teraz do listy typów zamków:
LockModeType.Optimistic
- Jeśli jednostki określają pole wersji, jest to pole domyślne. W przypadku jednostek bez kolumny wersji użycie tego typu blokady nie gwarantuje działania w żadnej implementacji JPA. Ten tryb jest zwykle ignorowany, jak określono w ObjectDB. Moim zdaniem istnieje tylko po to, aby można było dynamicznie obliczyć tryb blokady i przekazać go dalej, nawet jeśli blokada byłaby ostatecznie OPTYMISTYCZNA. Nie jest to jednak bardzo prawdopodobny przypadek użycia, ale zawsze dobrym projektem API jest zapewnienie opcji odwoływania się nawet do wartości domyślnej.
-
Przykład:
`LockModeType lockMode = resolveLockMode(); A a = em.find(A.class, 1, lockMode);`
LockModeType.OPTIMISTIC_FORCE_INCREMENT
- Jest to rzadko używana opcja. Ale może być rozsądne, jeśli chcesz zablokować odwoływanie się do tej encji przez inną encję. Innymi słowy, chcesz zablokować pracę z encją, nawet jeśli nie jest ona modyfikowana, ale inne encje mogą być modyfikowane w odniesieniu do tej encji.
- Przykład:Mamy księgę i półkę jednostki. Możliwe jest dodanie książki do półki, ale książka nie ma żadnego odniesienia do swojej półki. Rozsądne jest zablokowanie czynności przenoszenia książki na półkę, aby książka nie znalazła się na innej półce (z powodu innej transakcji) przed zakończeniem tej transakcji. Aby zablokować tę akcję, nie wystarczy zablokować bieżącą jednostkę półki książki, ponieważ książka nie musi jeszcze znajdować się na półce. Nie ma również sensu blokowanie wszystkich docelowych półek na książki, ponieważ prawdopodobnie byłyby różne w różnych transakcjach. Jedyną rzeczą, która ma sens, jest zablokowanie samej encji książki, nawet jeśli w naszym przypadku nie zostanie ona zmieniona (nie ma odniesienia do swojej półki z książkami).
LockModeType.PESSIMISTIC_READ
- ten tryb jest podobny do
LockModeType.PESSIMISTIC_WRITE
, ale różni się jednym:dopóki blokada zapisu nie zostanie nałożona na tę samą encję przez jakąś transakcję, nie powinna blokować odczytu encji. Umożliwia również blokowanie innych transakcji za pomocąLockModeType.PESSIMISTIC_READ
. Różnice między blokadami WRITE i READ są dobrze wyjaśnione tutaj (ObjectDB) i tutaj (OpenJPA). Jeśli jednostka jest już zablokowana przez inną transakcję, każda próba jej zablokowania spowoduje zgłoszenie wyjątku. To zachowanie można zmodyfikować tak, aby czekało przez pewien czas na zwolnienie blokady przed zgłoszeniem wyjątku i wycofaniem transakcji. W tym celu określjavax.persistence.lock.timeout
wskazówka z liczbą milisekund oczekiwania przed zgłoszeniem wyjątku. Można to zrobić na wiele sposobów na wielu poziomach, jak opisano w samouczku Java EE.
LockModeType.PESSIMISTIC_WRITE
- to silniejsza wersja
LockModeType.PESSIMISTIC_READ
. KiedyWRITE
blokada jest na miejscu, JPA z pomocą bazy danych uniemożliwi jakiejkolwiek innej transakcji odczytanie encji, a nie tylko zapis jak w przypadkuREAD
zablokuj. - Sposób, w jaki jest to zaimplementowane w dostawcy JPA we współpracy z bazową bazą danych, nie jest określony. W twoim przypadku z Oracle powiedziałbym, że Oracle nie zapewnia czegoś zbliżonego do
READ
Zamek.SELECT...FOR UPDATE
jest raczejWRITE
Zamek. Może to być błąd w hibernacji lub po prostu decyzja, że zamiast zaimplementować niestandardowe "miękkie"READ
blokada, „trudniejsze”WRITE
zamiast tego używany jest zamek. To w większości nie narusza spójności, ale nie utrzymuje wszystkich reguł zREAD
zamki. Możesz uruchomić kilka prostych testów za pomocąREAD
blokady i długotrwałe transakcje, aby dowiedzieć się, czy więcej transakcji może uzyskaćREAD
blokady na tej samej jednostce. Powinno to być możliwe, ale nie w przypadkuWRITE
zamki.
- LockModeType.PESSIMISTIC_FORCE_INCREMENT
- to kolejny rzadko używany tryb blokady. Jest to jednak opcja, w której musisz połączyć
PESSIMISTIC
iOPTIMISTIC
mechanizmy. Używanie zwykłegoPESSIMISTIC_WRITE
nie powiedzie się w następującym scenariuszu:- transakcja A używa optymistycznego blokowania i odczytuje encję E
- transakcja B uzyskuje blokadę WRITE na jednostce E
- transakcja B zatwierdza i zwalnia blokadę E
- transakcja A aktualizuje E i zatwierdza
- w kroku 4, jeśli kolumna wersji nie jest zwiększana przez transakcję B, nic nie stoi na przeszkodzie, aby A nadpisał zmiany B. Tryb blokady
LockModeType.PESSIMISTIC_FORCE_INCREMENT
zmusi transakcję B do aktualizacji numeru wersji i spowoduje niepowodzenie transakcji A zOptimisticLockException
, mimo że B używał pesymistycznego blokowania.
- LockModeType.BRAK
- jest to ustawienie domyślne, jeśli jednostki nie udostępniają pola wersji. Oznacza to, że żadne blokowanie nie jest włączone, konflikty będą rozwiązywane na zasadzie najlepszych starań i nie zostaną wykryte. To jedyny tryb blokady dozwolony poza transakcją