Ik zou eerst onderscheid maken tussen optimistische en pessimistische sloten, omdat ze verschillen in hun onderliggende mechanisme.
Optimistische vergrendeling wordt volledig beheerd door JPA en vereist alleen een extra versiekolom in DB-tabellen. Het is volledig onafhankelijk van de onderliggende DB-engine die wordt gebruikt om relationele gegevens op te slaan.
Aan de andere kant gebruikt pessimistische vergrendeling een vergrendelingsmechanisme dat wordt geleverd door de onderliggende database om bestaande records in tabellen te vergrendelen. JPA moet weten hoe deze vergrendelingen te activeren en sommige databases ondersteunen ze niet of slechts gedeeltelijk.
Nu naar de lijst met slottypes:
LockModeType.Optimistic
- Als entiteiten een versieveld specificeren, is dit de standaardinstelling. Voor entiteiten zonder een versiekolom kan het gebruik van dit type vergrendeling niet gegarandeerd werken op een JPA-implementatie. Deze modus wordt meestal genegeerd, zoals aangegeven door ObjectDB. Naar mijn mening bestaat het alleen zodat je de vergrendelingsmodus dynamisch kunt berekenen en verder kunt doorgeven, zelfs als de vergrendeling uiteindelijk OPTIMISTISCH zou zijn. Niet erg waarschijnlijk gebruik echter, maar het is altijd een goed API-ontwerp om een optie te bieden om zelfs naar de standaardwaarde te verwijzen.
-
Voorbeeld:
`LockModeType lockMode = resolveLockMode(); A a = em.find(A.class, 1, lockMode);`
LockModeType.OPTIMISTIC_FORCE_INCREMENT
- Dit is een zelden gebruikte optie. Maar het kan redelijk zijn als u de verwijzing naar deze entiteit door een andere entiteit wilt vergrendelen. Met andere woorden, u wilt het werken met een entiteit vergrendelen, zelfs als deze niet is gewijzigd, maar andere entiteiten kunnen worden gewijzigd met betrekking tot deze entiteit.
- Voorbeeld:we hebben entiteit Book and Shelf. Het is mogelijk om Boek aan plank toe te voegen, maar boek heeft geen verwijzing naar de plank. Het is redelijk om de actie van het verplaatsen van een boek naar een plank te vergrendelen, zodat een boek niet voor het einde van deze transactie op een andere plank belandt (vanwege een andere transactie). Om deze actie te vergrendelen, is het niet voldoende om de huidige boekenplankentiteit te vergrendelen, omdat het boek nog niet op een plank hoeft te staan. Het heeft ook geen zin om alle doelboekenplanken te vergrendelen, omdat ze bij verschillende transacties waarschijnlijk anders zouden zijn. Het enige dat logisch is, is om de boekentiteit zelf te vergrendelen, zelfs als deze in ons geval niet wordt gewijzigd (het bevat geen verwijzing naar zijn boekenplank).
LockModeType.PESSIMISTIC_READ
- deze modus is vergelijkbaar met
LockModeType.PESSIMISTIC_WRITE
, maar in één ding anders:totdat de schrijfvergrendeling door een transactie op dezelfde entiteit is geplaatst, mag het het lezen van de entiteit niet blokkeren. Het staat ook toe dat andere transacties worden vergrendeld metLockModeType.PESSIMISTIC_READ
. De verschillen tussen WRITE- en READ-locks worden hier (ObjectDB) en hier (OpenJPA) goed uitgelegd. Als een entiteit al is vergrendeld door een andere transactie, zal elke poging om deze te vergrendelen een uitzondering veroorzaken. Dit gedrag kan worden gewijzigd om enige tijd te wachten totdat de vergrendeling is vrijgegeven voordat een uitzondering wordt gegenereerd en de transactie wordt teruggedraaid. Om dat te doen, specificeert u dejavax.persistence.lock.timeout
hint met het aantal milliseconden dat moet worden gewacht voordat de uitzondering wordt gegenereerd. Er zijn meerdere manieren om dit op meerdere niveaus te doen, zoals beschreven in de Java EE-zelfstudie.
LockModeType.PESSIMISTIC_WRITE
- dit is een sterkere versie van
LockModeType.PESSIMISTIC_READ
. WanneerWRITE
slot op zijn plaats is, zal JPA met behulp van de database voorkomen dat elke andere transactie de entiteit leest, niet alleen om te schrijven zoals metREAD
slot. - De manier waarop dit wordt geïmplementeerd in een JPA-provider in samenwerking met onderliggende DB is niet voorgeschreven. In uw geval met Oracle zou ik zeggen dat Oracle niet iets biedt dat in de buurt komt van een
READ
slot.SELECT...FOR UPDATE
is eigenlijk eerder eenWRITE
slot. Het kan een bug zijn in de slaapstand of gewoon een beslissing die, in plaats van aangepaste "zachtere"READ
te implementeren, slot, de "hardere"WRITE
slot wordt in plaats daarvan gebruikt. Dit verbreekt meestal de consistentie niet, maar bevat niet alle regels metREAD
sloten. U kunt enkele eenvoudige tests uitvoeren metREAD
locks en langlopende transacties om erachter te komen of meer transactiesREAD
. kunnen verwerven sloten op dezelfde entiteit. Dit zou mogelijk moeten zijn, maar niet metWRITE
sloten.
- LockModeType.PESSIMISTIC_FORCE_INCREMENT
- dit is een andere zelden gebruikte vergrendelingsmodus. Het is echter een optie waarbij u
PESSIMISTIC
. moet combineren enOPTIMISTIC
mechanismen. Gebruik gewoonPESSIMISTIC_WRITE
zou mislukken in het volgende scenario:- transactie A gebruikt optimistische vergrendeling en leest entiteit E
- transactie B verwerft WRITE lock op entiteit E
- transactie B begaat en geeft slot van E vrij
- transactie A werkt E bij en verbindt zich
- in stap 4, als de versiekolom niet wordt verhoogd door transactie B, verhindert niets A de wijzigingen van B te overschrijven. Vergrendelmodus
LockModeType.PESSIMISTIC_FORCE_INCREMENT
dwingt transactie B om het versienummer bij te werken en zorgt ervoor dat transactie A mislukt metOptimisticLockException
, ook al gebruikte B pessimistische vergrendeling.
- LockModeType.NONE
- dit is de standaardinstelling als entiteiten geen versieveld bieden. Dit betekent dat er geen vergrendeling is ingeschakeld. Conflicten worden naar beste vermogen opgelost en niet gedetecteerd. Dit is de enige vergrendelingsmodus die buiten een transactie is toegestaan