Optimistisches Sperren in JPA

Optimistisches Locking in JPA

1. Einführung

Wenn es um Unternehmensanwendungen geht, ist es wichtig, den gleichzeitigen Zugriff auf eine Datenbank ordnungsgemäß zu verwalten. Dies bedeutet, dass wir in der Lage sein sollten, mehrere Transaktionen effektiv und vor allem fehlerfrei abzuwickeln.

Darüber hinaus müssen wir sicherstellen, dass die Daten zwischen gleichzeitigen Lesevorgängen und Aktualisierungen konsistent bleiben.

Um dies zu erreichen, können wir einen optimistischen Sperrmechanismus verwenden, der von der Java Persistence API bereitgestellt wird. Dies führt dazu, dass sich mehrere Aktualisierungen, die gleichzeitig an denselben Daten vorgenommen werden, nicht gegenseitig stören.

2. Grundlegendes zum optimistischen Sperren

Um eine optimistische Verriegelung zu verwenden, müssenwe need to have an entity including a property with @Version annotation. Während der Verwendung enthält jede Transaktion, die Daten liest, den Wert der Versionseigenschaft.

Bevor die Transaktion eine Aktualisierung vornehmen möchte, überprüft sie die Versionseigenschaft erneut.

Wenn sich der Wert in der Zwischenzeit geändert hat, wird einOptimisticLockException ausgelöst. Andernfalls schreibt die Transaktion die Aktualisierung fest und erhöht eine Werteversionseigenschaft.

3. Pessimistisches Locking vs. Optimistisches Sperren

Es ist gut zu wissen, dass JPA im Gegensatz zu optimistischem Sperren pessimistisches Sperren ermöglicht. Dies ist ein weiterer Mechanismus für den gleichzeitigen Zugriff auf Daten.

Wir behandeln pessimistisches Sperren in einem unserer vorherigen Artikel -Pessimistic Locking in JPA. Lassen Sie uns herausfinden, was der Unterschied ist und wie wir von jeder Art von Verriegelung profitieren können.

Wie bereits erwähnt,optimistic locking is based on detecting changes on entities by checking their version attribute. Wenn eine gleichzeitige Aktualisierung stattfindet, trittOptmisticLockException auf. Danach können wir erneut versuchen, die Daten zu aktualisieren.

Wir können uns vorstellen, dass dieser Mechanismus für Anwendungen geeignet ist, die viel mehr Lesevorgänge als Aktualisierungen oder Löschvorgänge ausführen. Darüber hinaus ist es in Situationen nützlich, in denen Entitäten für einige Zeit getrennt werden müssen und Sperren nicht gehalten werden können.

Im Gegensatz dazu beinhaltet der pessimistische Sperrmechanismus das Sperren von Entitäten auf Datenbankebene.

Jede Transaktion kann eine Datensperre erhalten. Solange die Sperre besteht, kann keine Transaktion die gesperrten Daten lesen, löschen oder aktualisieren. Wir können davon ausgehen, dass die Verwendung pessimistischer Sperren zu Deadlocks führen kann. Es gewährleistet jedoch eine größere Datenintegrität als optimistisches Sperren.

4. Versionsattribute

Versionsattribute sind Eigenschaften mit der Annotation@Version. They are necessary for enabling optimistic locking. Sehen wir uns eine Beispielentitätsklasse an:

@Entity
public class Student {

    @Id
    private Long id;

    private String name;

    private String lastName;

    @Version
    private Integer version;

    // getters and setters

}

Es gibt mehrere Regeln, denen wir beim Deklarieren von Versionsattributen folgen sollten:

  • Jede Entitätsklasse darf nur ein Versionsattribut haben

  • Es muss in der Primärtabelle für eine Entität platziert werden, die mehreren Tabellen zugeordnet ist

  • Der Typ eines Versionsattributs muss einer der folgenden sein:int,Integer,long,Long,short,Short,java.sql.Timestamp

We should know that we can retrieve a value of the version attribute via entity, but we mustn’t update or increment it. Dies kann nur der Persistenzanbieter, sodass die Daten konsistent bleiben.

Es ist zu beachten, dass Persistenzanbieter optimistisches Sperren für Entitäten unterstützen können, die keine Versionsattribute haben. Es ist jedoch eine gute Idee, bei der Arbeit mit optimistischem Sperren immer Versionsattribute einzubeziehen.

Wenn wir versuchen, eine Entität zu sperren, die ein solches Attribut nicht enthält und der Persistenzanbieter es nicht unterstützt, führt dies zu einemPersitenceException.

5. Sperrmodi

JPA bietet uns zwei verschiedene optimistische Sperrmodi (und zwei Aliase):

  • OPTIMISTIC - Es wird eine optimistische Lesesperre für alle Entitäten erhalten, die ein Versionsattribut enthalten

  • OPTIMISTIC_FORCE_INCREMENT - Es erhält eine optimistische Sperre wieOPTIMISTIC und erhöht zusätzlich den Versionsattributwert

  • READ - Dies ist ein Synonym fürOPTIMISTIC

  • WRITE - Dies ist ein Synonym fürOPTIMISTIC_FORCE_INCREMENT

Wir können alle oben aufgeführten Typen in der KlasseLockModeTypefinden.

5.1. OPTIMISTIC (READ)

Wie wir bereits wissen, sind die SperrmodiOPTIMISTIC undREADynonyme. In der JPA-Spezifikation wird jedoch empfohlen,OPTIMISTIC in neuen Anwendungen zu verwenden.

Whenever we request the OPTIMISTIC lock mode, a persistence provider will prevent our data from dirty reads as well as non-repeatable reads.

Einfach ausgedrückt sollte es sicherstellen, dass keine Transaktion Änderungen an Daten festschreibt, die von einer anderen Transaktion vorgenommen wurden:

  • wurde aktualisiert oder gelöscht, aber nicht festgeschrieben

  • hat in der Zwischenzeit erfolgreich aktualisiert oder gelöscht

5.2. OPTIMISTIC_INCREMENT (WRITE)

OPTIMISTIC_INCREMENT undWRITE sind wie zuvor Synonyme, wobei erstere vorzuziehen sind.

OPTIMISTIC_INCREMENT müssen die gleichen Bedingungen erfüllen wie der Sperrmodus vonOPTIMISTIC. Additionally, it increments the value of a version attribute. Es ist jedoch nicht festgelegt, ob dies sofort erfolgen soll oder bis zum Festschreiben oder Löschen verschoben werden soll.

Es ist wichtig zu wissen, dass ein Persistenzanbieter die Funktionalität vonOPTIMISTIC_INCREMENTbereitstellen darf, wenn der Sperrmodus vonOPTIMISTICangefordert wird.

6. Optimistic Locking verwenden

We should remember that for versioned entities optimistic locking is available by default. Es gibt jedoch verschiedene Möglichkeiten, dies explizit anzufordern.

6.1. Find

Um ein optimistisches Sperren anzufordern, können wir die richtigenLockModeType als Argument übergeben, um die Methode vonEntityManager zu finden:

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

6.2. Abfrage

Eine andere Möglichkeit, das Sperren zu aktivieren, ist die Verwendung dersetLockMode-Methode desQuery-Objekts:

Query query = entityManager.createQuery("from Student where id = :id");
query.setParameter("id", studentId);
query.setLockMode(LockModeType.OPTIMISTIC_INCREMENT);
query.getResultList()

6.3. Explizites Sperren

Wir können eine Sperre setzen, indem wir dielock-Methode von EnitityManager aufrufen:

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

6.4. Aktualisierung

Wir können dierefresh-Methode genauso aufrufen wie die vorherige Methode:

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

6.5. NamedQuery

Die letzte Option besteht darin, @NamedQuery mit der EigenschaftlockModezu verwenden:

@NamedQuery(name="optimisticLock",
  query="SELECT s FROM Student s WHERE s.id LIKE :id",
  lockMode = WRITE)

7. OptimisticLockException

When the persistence provider discovers optimistic locking conflicts on entities, it throws OptimisticLockExceptionWir sollten uns bewusst sein, dass aufgrund der Ausnahme die aktive Transaktion immer für das Rollback markiert ist.

Es ist gut zu wissen, wie wir aufOptimisticLockExceptionreagieren können. Zweckmäßigerweise enthält diese Ausnahme einen Verweis auf die in Konflikt stehende Entität. However, it’s not mandatory for the persistence provider to supply it in every situation. Es gibt keine Garantie, dass das Objekt verfügbar sein wird.

Es wird jedoch empfohlen, die beschriebene Ausnahme zu behandeln. Wir sollten die Entität erneut abrufen, indem wir sie neu laden oder aktualisieren. Am besten in einer neuen Transaktion. Danach können wir versuchen, es noch einmal zu aktualisieren.

8. Fazit

In diesem Tutorial haben wir uns mit einem Tool vertraut gemacht, mit dessen Hilfe wir gleichzeitige Transaktionen koordinieren können. Optimistic locking uses version attributes included in entities to control concurrent modifications on them.

Daher wird sichergestellt, dass Aktualisierungen oder Löschungen nicht überschrieben werden oder stillschweigend verloren gehen. Im Gegensatz zum pessimistischen Sperren werden keine Entitäten auf Datenbankebene gesperrt, und folglich ist es nicht anfällig für DB-Deadlocks.

Wir haben erfahren, dass das optimistische Sperren für versionierte Entitäten standardmäßig aktiviert ist. Es gibt jedoch mehrere Möglichkeiten, dies explizit anzufordern, indem verschiedene Sperrmodustypen verwendet werden.

Eine weitere Tatsache, an die wir uns erinnern sollten, ist, dass wir jedes Mal, wenn es widersprüchliche Aktualisierungen von Entitäten gibt, einOptimisticLockExceptionerwarten sollten.

Schließlich ist der Quellcode dieses Tutorialsover on GitHub verfügbar.