Optimistische vergrendeling in JPA

1. Inleiding

Als het gaat om bedrijfstoepassingen, is het cruciaal om de gelijktijdige toegang tot een database correct te beheren. Dit betekent dat we meerdere transacties op een effectieve en vooral foutbestendige manier moeten kunnen afhandelen.

Bovendien moeten we ervoor zorgen dat gegevens consistent blijven tussen gelijktijdige leesbewerkingen en updates.

Om dat te bereiken, kunnen we een optimistisch vergrendelingsmechanisme gebruiken dat wordt geleverd door de Java Persistence API. Het leidt ertoe dat meerdere updates die tegelijkertijd op dezelfde gegevens worden aangebracht, elkaar niet storen.

2. Optimistische vergrendeling begrijpen

Om optimistische vergrendeling te gebruiken, we moeten een entiteit hebben met een eigendom bij @Versie annotatie. Tijdens het gebruik ervan bevat elke transactie die gegevens leest de waarde van de eigenschap version.

Voordat de transactie een update wil uitvoeren, wordt de versie-eigenschap opnieuw gecontroleerd.

Als de waarde in de tussentijd is gewijzigd, kan een OptimisticLockException wordt gegooid. Anders legt de transactie de update vast en verhoogt de waarde van een versie-eigenschap.

3. Pessimistische vergrendeling versus optimistische vergrendeling

Het is goed om te weten dat JPA, in tegenstelling tot optimistische vergrendeling, ons pessimistische vergrendeling geeft. Het is een ander mechanisme voor het afhandelen van gelijktijdige toegang tot gegevens.

We behandelen pessimistische vergrendeling in een van onze vorige artikelen - Pessimistische vergrendeling in JPA. Laten we kijken wat het verschil is en hoe we kunnen profiteren van elk type vergrendeling.

Zoals we al eerder hebben gezegd, optimistische vergrendeling is gebaseerd op het detecteren van wijzigingen op entiteiten door hun versiekenmerk te controleren. Als er een gelijktijdige update plaatsvindt, OptmisticLockException treedt op. Daarna kunnen we opnieuw proberen de gegevens bij te werken.

We kunnen ons voorstellen dat dit mechanisme geschikt is voor applicaties die veel meer kunnen lezen dan updaten of verwijderen. Bovendien is het handig in situaties waarin entiteiten enige tijd moeten worden losgemaakt en vergrendelingen niet kunnen worden vastgehouden.

Integendeel, een pessimistisch vergrendelingsmechanisme omvat het vergrendelen van entiteiten op databaseniveau.

Elke transactie kan een gegevensvergrendeling krijgen. Zolang het de vergrendeling vasthoudt, kan geen enkele transactie de vergrendelde gegevens lezen, verwijderen of bijwerken. We kunnen aannemen dat het gebruik van pessimistische vergrendeling kan leiden tot impasses. Het zorgt echter voor een grotere integriteit van gegevens dan een optimistische vergrendeling.

4. Versiekenmerken

Versiekenmerken zijn eigenschappen met @Versie annotatie. Ze zijn nodig om een ‚Äč‚Äčoptimistische vergrendeling mogelijk te maken. Laten we een voorbeeld van een entiteitsklasse bekijken:

@Entity openbare klas Student {@Id privé Lange id; private String naam; private String achternaam; @Version private Integer-versie; // getters en setters}

Er zijn verschillende regels die we moeten volgen bij het declareren van versiekenmerken:

  • elke entiteitsklasse mag slechts één versiekenmerk hebben
  • het moet in de primaire tabel worden geplaatst voor een entiteit die is toegewezen aan verschillende tabellen
  • type van een versiekenmerk moet een van de volgende zijn: int, Geheel getal, lang, Lang, kort, Kort, java.sql.Timestamp

We moeten weten dat we een waarde van het versiekenmerk kunnen ophalen via entiteit, maar we mogen het niet bijwerken of verhogen. Alleen de persistentieleverancier kan dat doen, zodat de gegevens consistent blijven.

Het is vermeldenswaard dat persistentieproviders optimistische vergrendeling kunnen ondersteunen voor entiteiten die geen versieattributen hebben. Toch is het een goed idee om altijd versiekenmerken op te nemen bij het werken met optimistische vergrendeling.

Als we een entiteit proberen te vergrendelen die een dergelijk attribuut niet bevat en de persistentieprovider dit niet ondersteunt, zal dit resulteren in een PersitenceException.

5. Vergrendelmodi

JPA biedt ons twee verschillende optimistische vergrendelingsmodi (en twee aliassen):

  • OPTIMISTISCH - het krijgt een optimistische leesvergrendeling voor alle entiteiten die een versiekenmerk bevatten
  • OPTIMISTIC_FORCE_INCREMENT - het krijgt hetzelfde optimistische slot als OPTIMISTISCH en verhoogt bovendien de waarde van het versieattribuut
  • LEZEN - het is een synoniem voor OPTIMISTISCH
  • SCHRIJVEN - het is een synoniem voor OPTIMISTIC_FORCE_INCREMENT

We kunnen alle hierboven genoemde typen vinden in de LockModeType klasse.

5.1. OPTIMISTISCH (LEZEN)

Zoals we al weten, OPTIMISTISCH en LEZEN lock-modi zijn synoniemen. De JPA-specificatie raadt ons echter aan om te gebruiken OPTIMISTISCH in nieuwe toepassingen.

Telkens wanneer we het OPTIMISTISCH lock-modus, zal een persistentieprovider voorkomen dat onze gegevens zowel vuile als niet-herhaalbare leesbewerkingen bevatten.

Simpel gezegd, het zou ervoor moeten zorgen dat elke transactie geen enkele wijziging aanbrengt in gegevens die een andere transactie:

  • is bijgewerkt of verwijderd maar niet vastgelegd
  • is ondertussen met succes bijgewerkt of verwijderd

5.2. OPTIMISTIC_INCREMENT (SCHRIJVEN)

Hetzelfde als voorheen, OPTIMISTIC_INCREMENT en SCHRIJVEN zijn synoniemen, maar de eerste verdient de voorkeur.

OPTIMISTIC_INCREMENT moet aan dezelfde voorwaarden voldoen als OPTIMISTISCH gesloten modus. Bovendien verhoogt het de waarde van een versiekenmerk. Het is echter niet gespecificeerd of het onmiddellijk moet worden gedaan of mag worden uitgesteld tot commit of flush.

Het is de moeite waard om te weten dat een persistentieprovider mag verstrekken OPTIMISTIC_INCREMENT functionaliteit wanneer OPTIMISTISCH lock-modus wordt gevraagd.

6. Optimistische vergrendeling gebruiken

We moeten niet vergeten dat voor entiteiten met versiebeheer standaard optimistische vergrendeling beschikbaar is. Toch zijn er verschillende manieren om dit expliciet aan te vragen.

6.1. Vind

Om optimistische vergrendeling te vragen, kunnen we de juiste doorgeven LockModeType als argument om de methode van te vinden EntityManager:

entiteitManager.find (Student.class, studentId, LockModeType.OPTIMISTIC);

6.2. Vraag

Een andere manier om vergrendeling in te schakelen, is door de setLockMode methode van Vraag voorwerp:

Queryquery = entityManager.createQuery ("van student waarbij id =: id"); query.setParameter ("id", studentId); query.setLockMode (LockModeType.OPTIMISTIC_INCREMENT); query.getResultList ()

6.3. Expliciete vergrendeling

We kunnen een slot zetten door EnitityManager te bellen slot methode:

Student student = entityManager.find (Student.class, id); entiteitManager.lock (student, LockModeType.OPTIMISTIC);

6.4. Vernieuwen

We kunnen de vernieuwen methode op dezelfde manier als de vorige methode:

Student student = entityManager.find (Student.class, id); entiteitManager.refresh (student, LockModeType.READ);

6.5. NamedQuery

De laatste optie is om @NamedQuery te gebruiken met de gesloten modus eigendom:

@NamedQuery (name = "optimisticLock", query = "SELECTEER s VAN STUDENTEN WAAR s.id LIKE: id", lockMode = SCHRIJF)

7. OptimisticLockException

Wanneer de persistentieprovider optimistische vergrendelingsconflicten op entiteiten ontdekt, gooit het OptimisticLockException. We moeten ons ervan bewust zijn dat vanwege de uitzondering de actieve transactie altijd gemarkeerd is voor terugdraaien.

Het is goed om te weten hoe we erop kunnen reageren OptimisticLockException. Gemakshalve bevat deze uitzondering een verwijzing naar de conflicterende entiteit. Het is echter niet verplicht voor de persistentieprovider om deze in elke situatie te leveren. Er is geen garantie dat het object beschikbaar zal zijn.

Er is echter een aanbevolen manier om met de beschreven uitzondering om te gaan. We moeten de entiteit opnieuw ophalen door opnieuw te laden of te vernieuwen. Bij voorkeur in een nieuwe transactie. Daarna kunnen we proberen het nog een keer bij te werken.

8. Conclusie

In deze tutorial hebben we kennis gemaakt met een tool die ons kan helpen bij het orkestreren van gelijktijdige transacties. Optimistische vergrendeling maakt gebruik van versieattributen die in entiteiten zijn opgenomen om gelijktijdige wijzigingen daarop te controleren.

Daarom zorgt het ervoor dat updates of verwijderingen niet worden overschreven of stilzwijgend verloren gaan. In tegenstelling tot pessimistische vergrendeling, vergrendelt het geen entiteiten op databaseniveau en is het bijgevolg niet kwetsbaar voor DB-impasses.

We hebben geleerd dat optimistische vergrendeling standaard is ingeschakeld voor entiteiten met versiebeheer. Er zijn echter verschillende manieren om dit expliciet aan te vragen door verschillende soorten vergrendelingsmodi te gebruiken.

Een ander feit dat we moeten onthouden, is dat we elke keer dat er tegenstrijdige updates over entiteiten zijn, een OptimisticLockException.

Ten slotte is de broncode van deze tutorial beschikbaar op GitHub.