Ich würde zunächst zwischen optimistischen und pessimistischen Sperren unterscheiden, da sie sich in ihrem zugrunde liegenden Mechanismus unterscheiden.
Optimistisches Sperren wird vollständig von JPA gesteuert und erfordert nur eine zusätzliche Versionsspalte in DB-Tabellen. Es ist völlig unabhängig von der zugrunde liegenden DB-Engine, die zum Speichern relationaler Daten verwendet wird.
Auf der anderen Seite verwendet das pessimistische Sperren einen Sperrmechanismus, der von der zugrunde liegenden Datenbank bereitgestellt wird, um vorhandene Datensätze in Tabellen zu sperren. JPA muss wissen, wie diese Sperren ausgelöst werden, und einige Datenbanken unterstützen sie nicht oder nur teilweise.
Nun zur Liste der Sperrtypen:
LockModeType.Optimistic
- Wenn Entitäten ein Versionsfeld angeben, ist dies die Voreinstellung. Bei Entitäten ohne Versionsspalte funktioniert die Verwendung dieser Art von Sperre nicht garantiert bei jeder JPA-Implementierung. Dieser Modus wird normalerweise ignoriert, wie von ObjectDB angegeben. Meiner Meinung nach existiert es nur, damit Sie den Sperrmodus dynamisch berechnen und weitergeben können, selbst wenn die Sperre am Ende OPTIMISTISCH wäre. Nicht sehr wahrscheinlicher Anwendungsfall, aber es ist immer ein gutes API-Design, eine Option bereitzustellen, um sogar auf den Standardwert zu verweisen.
-
Beispiel:
`LockModeType lockMode = resolveLockMode(); A a = em.find(A.class, 1, lockMode);`
LockModeType.OPTIMISTIC_FORCE_INCREMENT
- Dies ist eine selten verwendete Option. Aber es könnte sinnvoll sein, wenn Sie die Referenzierung dieser Entität durch eine andere Entität sperren möchten. Mit anderen Worten, Sie möchten die Arbeit mit einer Entität sperren, auch wenn sie nicht geändert wurde, aber andere Entitäten können in Bezug auf diese Entität geändert werden.
- Beispiel:Wir haben die Entität Book and Shelf. Es ist möglich, ein Buch zum Regal hinzuzufügen, aber das Buch hat keinen Verweis auf sein Regal. Es ist sinnvoll, das Verschieben eines Buches in ein Regal zu sperren, damit ein Buch nicht vor Ende dieser Transaktion (aufgrund einer anderen Transaktion) in einem anderen Regal landet. Um diese Aktion zu sperren, reicht es nicht aus, die aktuelle Bücherregalentität zu sperren, da das Buch noch nicht in einem Regal stehen muss. Es macht auch keinen Sinn, alle Ziel-Bücherregale zu sperren, da sie wahrscheinlich in verschiedenen Transaktionen unterschiedlich sein würden. Das einzige, was Sinn macht, ist, die Buchentität selbst zu sperren, auch wenn sie in unserem Fall nicht geändert wird (sie enthält keinen Verweis auf ihr Bücherregal).
LockModeType.PESSIMISTIC_READ
- dieser Modus ähnelt
LockModeType.PESSIMISTIC_WRITE
, aber in einer Sache anders:Bis eine Schreibsperre für dieselbe Entität durch eine Transaktion eingerichtet ist, sollte das Lesen der Entität nicht blockiert werden. Außerdem können andere Transaktionen mitLockModeType.PESSIMISTIC_READ
gesperrt werden . Die Unterschiede zwischen WRITE- und READ-Sperren werden hier (ObjectDB) und hier (OpenJPA) gut erklärt. Wenn eine Entität bereits durch eine andere Transaktion gesperrt ist, löst jeder Versuch, sie zu sperren, eine Ausnahme aus. Dieses Verhalten kann so geändert werden, dass einige Zeit gewartet wird, bis die Sperre freigegeben wird, bevor eine Ausnahme ausgelöst und die Transaktion rückgängig gemacht wird. Geben Sie dazujavax.persistence.lock.timeout
an Hinweis mit der Anzahl der zu wartenden Millisekunden, bevor die Ausnahme ausgelöst wird. Es gibt mehrere Möglichkeiten, dies auf mehreren Ebenen zu tun, wie im Java EE-Tutorial beschrieben.
LockModeType.PESSIMISTIC_WRITE
- Dies ist eine stärkere Version von
LockModeType.PESSIMISTIC_READ
. BeimWRITE
Wenn eine Sperre vorhanden ist, verhindert JPA mit Hilfe der Datenbank, dass andere Transaktionen die Entität lesen und nicht nur schreiben, wie mitREAD
sperren. - Die Art und Weise, wie dies in einem JPA-Anbieter in Zusammenarbeit mit der zugrunde liegenden DB implementiert wird, ist nicht vorgeschrieben. In Ihrem Fall mit Oracle würde ich sagen, dass Oracle nichts in der Nähe eines
READ
bietet sperren.SELECT...FOR UPDATE
ist eigentlich eher einWRITE
sperren. Es kann ein Fehler im Ruhezustand sein oder nur eine Entscheidung, statt benutzerdefinierten "weicheren"READ
zu implementieren lock, das "härtere"WRITE
Sperre wird stattdessen verwendet. Dies bricht meistens nicht die Konsistenz, hält aber nicht alle Regeln mitREAD
Schlösser. Sie könnten einige einfache Tests mitREAD
ausführen Sperren und Transaktionen mit langer Laufzeit, um herauszufinden, ob weitere TransaktionenREAD
erwerben können sperrt dieselbe Entität. Dies sollte möglich sein, nicht jedoch mitWRITE
Schlösser.
- LockModeType.PESSIMISTIC_FORCE_INCREMENT
- Dies ist ein weiterer selten verwendeter Sperrmodus. Es ist jedoch eine Option, bei der Sie
PESSIMISTIC
kombinieren müssen undOPTIMISTIC
Mechanismen. Verwenden von einfachemPESSIMISTIC_WRITE
würde in folgendem Szenario fehlschlagen:- Transaktion A verwendet optimistisches Sperren und liest Entität E
- Transaktion B erwirbt WRITE-Sperre auf Entität E
- Transaktion B schreibt fest und gibt Sperre von E frei
- Transaktion A aktualisiert E und schreibt fest
- in Schritt 4, wenn die Versionsspalte nicht durch Transaktion B inkrementiert wird, hindert nichts A daran, Änderungen von B zu überschreiben. Sperrmodus
LockModeType.PESSIMISTIC_FORCE_INCREMENT
zwingt Transaktion B, die Versionsnummer zu aktualisieren, und bewirkt, dass Transaktion A mitOptimisticLockException
fehlschlägt , obwohl B pessimistische Sperren verwendet hat.
- LockModeType.NONE
- Dies ist die Standardeinstellung, wenn Entitäten kein Versionsfeld bereitstellen. Dies bedeutet, dass keine Sperre aktiviert ist. Konflikte werden nach besten Kräften gelöst und nicht erkannt. Dies ist der einzige Sperrmodus, der außerhalb einer Transaktion erlaubt ist