Wie funktioniert @Version
Annotation in JPA?
Ich habe verschiedene Antworten gefunden, deren Auszug wie folgt lautet:
JPA verwendet ein Versionsfeld in Ihren Entitäten, um gleichzeitige Änderungen am gleichen Datenspeicherdatensatz zu erkennen. Wenn die JPA-Laufzeit einen Versuch erkennt, denselben Datensatz gleichzeitig zu ändern, wird eine Ausnahme für die Transaktion ausgelöst, die versucht, zuletzt einen Commit durchzuführen.
Aber ich bin mir immer noch nicht sicher, wie es funktioniert.
Auch ab folgenden Zeilen:
Sie sollten Versionsfelder als unveränderlich betrachten. Das Ändern des Feldwerts hat undefinierte Ergebnisse.
Bedeutet das, dass wir unser Versionsfeld als deklarieren sollten final
?
java
jpa
jpa-annotations
Yatendra Goel
quelle
quelle
UPDATE myentity SET mycolumn = 'new value', version = version + 1 WHERE version = [old.version]
. Wenn jemand den Datensatz aktualisiert hat,old.version
stimmt er nicht mehr mit dem in der Datenbank überein, und die where-Klausel verhindert, dass das Update durchgeführt wird. Die 'aktualisierten Zeilen' werden von0
JPA erkannt, um zu schließen, dass eine gleichzeitige Änderung stattgefunden hat.Antworten:
Angenommen, eine Entität
MyEntity
verfügt über eine mit Anmerkungen verseheneversion
Eigenschaft:Bei der Aktualisierung wird das mit Anmerkungen versehene Feld
@Version
inkrementiert und derWHERE
Klausel hinzugefügt.Wenn die
WHERE
Klausel nicht mit einem Datensatz übereinstimmt (da dieselbe Entität bereits von einem anderen Thread aktualisiert wurde), gibt der Persistenzanbieter einen ausOptimisticLockException
.Nein, aber Sie könnten in Betracht ziehen, den Setter zu schützen, da Sie ihn nicht nennen sollten.
quelle
long
oder es einfach aufzurufenlongValue()
. Sie benötigen explizitenull
Überprüfungen. Eine explizite Initialisierung würde ich nicht tun, da dieses Feld vom ORM-Anbieter verwaltet werden soll. Ich denke, es wird0L
beim ersten Einfügen in die Datenbank auf gesetzt. Wenn es also aufnull
diesen Wert gesetzt ist, wird Ihnen mitgeteilt, dass dieser Datensatz noch nicht beibehalten wurde.Long
als ein Grundelementlong
für das@Version
Feld zu verwenden, daSimpleJpaRepository.save(entity)
ein Feld mit der Nullversion wahrscheinlich als Indikator dafür behandelt wird, dass die Entität neu ist. Wenn die Entität neu ist (wie durch die Version null angegeben), ruft Spring aufem.persist(entity)
. Wenn die Version jedoch einen Wert hat, wird sie aufgerufenem.merge(entity)
. Aus diesem Grund sollte ein Versionsfeld, das als Wrapper-Typ deklariert ist, nicht initialisiert werden.Obwohl die Antwort von @Pascal vollkommen gültig ist, finde ich aus meiner Erfahrung den folgenden Code hilfreich, um ein optimistisches Sperren zu erreichen:
Warum? Weil:
@Version
istnull
.optlock
anstatt irreführend zu seinversion
.Erster Punkt spielt keine Rolle , wenn Anwendung verwendet nur JPA für Daten in die Datenbank einfügen, als PPV - Anbieter erzwingen wird
0
für@version
Feld zum Zeitpunkt der Erstellung. Es werden jedoch fast immer auch einfache SQL-Anweisungen verwendet (zumindest während Unit- und Integrationstests).quelle
u_lmod
(zuletzt geänderter Benutzer), wobei der Benutzer ein menschlicher oder definierter (automatisierter) Prozess / eine Entität / eine App sein kann (daheru_lmod_id
könnte das Speichern zusätzlich auch sinnvoll sein). (Es ist meiner Ansicht nach ein sehr grundlegendes Business-Meta-Attribut). Es speichert normalerweise seinen Wert als DATE (TIME) (dh Infos über Jahr ... Millis) in UTC (wenn es wichtig ist, die Zeitzone "Position" des Editors zu speichern, dann mit Zeitzone). Darüber hinaus sehr nützlich für DWH-Synchronisierungsszenarien.Jedes Mal, wenn eine Entität in der Datenbank aktualisiert wird, wird das Versionsfeld um eins erhöht. Jede Operation, die die Entität in der Datenbank aktualisiert, wird an
WHERE version = VERSION_THAT_WAS_LOADED_FROM_DATABASE
ihre Abfrage angehängt .Bei der Überprüfung der betroffenen Zeilen Ihres Vorgangs kann das jpa-Framework sicherstellen, dass zwischen dem Laden und dem Beibehalten Ihrer Entität keine gleichzeitigen Änderungen vorgenommen wurden, da die Abfrage Ihre Entität nicht in der Datenbank finden würde, wenn die Versionsnummer zwischen Laden und Beibehalten erhöht wurde.
quelle
Version, die verwendet wird, um sicherzustellen, dass jeweils nur ein Update durchgeführt wird. Der JPA-Anbieter überprüft die Version. Wenn sich die erwartete Version bereits erhöht, aktualisiert bereits eine andere Person die Entität, sodass eine Ausnahme ausgelöst wird.
Das Aktualisieren des Entitätswerts wäre also sicherer und optimistischer.
Wenn sich der Wert häufig ändert, sollten Sie möglicherweise das Versionsfeld nicht verwenden. Zum Beispiel "eine Entität mit einem Zählerfeld, die sich bei jedem Zugriff auf eine Webseite erhöht"
quelle
Fügen Sie einfach ein wenig mehr Informationen hinzu.
JPA verwaltet die Version unter der Haube für Sie, tut dies jedoch nicht, wenn Sie Ihren Datensatz über aktualisieren
JPAUpdateClause
. In solchen Fällen müssen Sie das Versionsinkrement manuell zur Abfrage hinzufügen.Gleiches gilt für die Aktualisierung über JPQL, dh nicht für eine einfache Änderung der Entität, sondern für einen Aktualisierungsbefehl für die Datenbank, selbst wenn dies im Ruhezustand erfolgt
Pedro
quelle
JPAUpdateClause
?