Jeg vil først skelne mellem optimistiske og pessimistiske låse, fordi de er forskellige i deres underliggende mekanisme.
Optimistisk låsning er fuldt styret af JPA og kræver kun yderligere versionskolonne i DB-tabeller. Den er fuldstændig uafhængig af den underliggende DB-motor, der bruges til at lagre relationelle data.
På den anden side bruger pessimistisk låsning låsemekanisme leveret af den underliggende database til at låse eksisterende poster i tabeller. JPA skal vide, hvordan man udløser disse låse, og nogle databaser understøtter dem ikke eller kun delvist.
Nu til listen over låsetyper:
LockModeType.Optimistic
- Hvis enheder angiver et versionsfelt, er dette standard. For enheder uden en versionskolonne er det ikke garanteret, at brug af denne type lås virker på nogen JPA-implementering. Denne tilstand ignoreres normalt som angivet af ObjectDB. Efter min mening eksisterer den kun, så du kan beregne låsetilstand dynamisk og sende den videre, selvom låsen ville være OPTIMISTISK i sidste ende. Dog ikke særlig sandsynligt, men det er altid et godt API-design at give mulighed for at referere til selv standardværdien.
-
Eksempel:
`LockModeType lockMode = resolveLockMode(); A a = em.find(A.class, 1, lockMode);`
LockModeType.OPTIMISTIC_FORCE_INCREMENT
- Dette er en sjældent brugt mulighed. Men det kunne være rimeligt, hvis du ønsker at låse henvisning til denne enhed af en anden enhed. Med andre ord vil du låse arbejdet med en enhed, selvom den ikke er ændret, men andre entiteter kan blive ændret i forhold til denne enhed.
- Eksempel:Vi har entitetsbog og -hylde. Det er muligt at tilføje bog til hylde, men bogen har ingen reference til dens hylde. Det er rimeligt at låse handlingen med at flytte en bog til en hylde, så en bog ikke ender i en anden hylde (på grund af en anden transaktion) inden afslutningen af denne transaktion. For at låse denne handling er det ikke tilstrækkeligt at låse den aktuelle boghyldeentitet, da bogen ikke behøver at være på en hylde endnu. Det giver heller ikke mening at låse alle målbogreoler, da de sandsynligvis ville være forskellige i forskellige transaktioner. Det eneste, der giver mening er at låse selve bogentiteten, selvom den i vores tilfælde ikke bliver ændret (den har ikke reference til dens bogreol).
LockModeType.PESSIMISTIC_READ
- denne tilstand ligner
LockModeType.PESSIMISTIC_WRITE
, men forskellig på én ting:indtil skrivelås er på plads på den samme enhed ved en transaktion, bør den ikke blokere for læsning af enheden. Det tillader også andre transaktioner at låse ved hjælp afLockModeType.PESSIMISTIC_READ
. Forskellene mellem WRITE- og READ-låse er godt forklaret her (ObjectDB) og her (OpenJPA). Hvis en enhed allerede er låst af en anden transaktion, vil ethvert forsøg på at låse den medføre en undtagelse. Denne adfærd kan ændres til at vente et stykke tid på, at låsen frigives, før du kaster en undtagelse og ruller transaktionen tilbage. For at gøre det skal du angivejavax.persistence.lock.timeout
antyde antallet af millisekunder, du skal vente, før du kaster undtagelsen. Der er flere måder at gøre dette på på flere niveauer, som beskrevet i Java EE tutorial.
LockModeType.PESSIMISTIC_WRITE
- dette er en stærkere version af
LockModeType.PESSIMISTIC_READ
. NårWRITE
låsen er på plads, vil JPA ved hjælp af databasen forhindre enhver anden transaktion for at læse enheden, ikke kun at skrive som medREAD
lås. - Måden hvordan dette implementeres i en JPA-udbyder i samarbejde med underliggende DB er ikke foreskrevet. I dit tilfælde med Oracle vil jeg sige, at Oracle ikke giver noget nær en
READ
låse.SELECT...FOR UPDATE
er egentlig snarere enWRITE
låse. Det kan være en fejl i dvaletilstand eller bare en beslutning, der i stedet for at implementere brugerdefineret "blødere"READ
lås, jo "hårdere"WRITE
lås bruges i stedet. Dette bryder for det meste ikke konsistensen, men holder ikke alle regler medREAD
låse. Du kan køre nogle simple tests medREAD
låse og langvarige transaktioner for at finde ud af, om flere transaktioner er i stand til at erhverveREAD
låser på den samme enhed. Dette burde være muligt, hvorimod ikke medWRITE
låse.
- LockModeType.PESSIMISTIC_FORCE_INCREMENT
- dette er en anden sjældent brugt låsetilstand. Det er dog en mulighed, hvor du skal kombinere
PESSIMISTIC
ogOPTIMISTIC
mekanismer. Bruger almindeligPESSIMISTIC_WRITE
ville mislykkes i følgende scenarie:- Transaktion A bruger optimistisk låsning og læser enhed E
- Transaktion B erhverver WRITE-lås på enhed E
- transaktion B forpligter og frigiver lås af E
- Transaktion A opdaterer E og forpligter
- i trin 4, hvis versionskolonnen ikke øges af transaktion B, forhindrer intet A i at overskrive ændringer af B. Låsetilstand
LockModeType.PESSIMISTIC_FORCE_INCREMENT
vil tvinge transaktion B til at opdatere versionsnummeret og få transaktion A til at mislykkes medOptimisticLockException
, selvom B brugte pessimistisk låsning.
- LockModeType.NONE
- dette er standard, hvis enheder ikke leverer et versionsfelt. Det betyder, at ingen låsning er aktiveret, konflikter vil blive løst efter bedste indsats og vil ikke blive opdaget. Dette er den eneste låsetilstand, der er tilladt uden for en transaktion