Es gibt eine Entität Foo
mit einer @Version
-Spalte. Wenn ich es löschen möchte, erwarte ich Spring Data JPA und / oder Hibernate, um zu überprüfen, ob der aktuelle Wert der Spalte @Version
mit dem in der Datenbank übereinstimmt. Wenn dies nicht der Fall ist, sollte die Löschung abgelehnt werden. Dies funktioniert wie erwartet mit einer getrennten Entität:
Wenn ich jedoch die Entity zuerst aus dem Repository lade und sie dann innerhalb derselben Transaktion mit einer anderen Version lösche, wird die Löschung unabhängig vom Wert von @Version
column:
Wenn ich in die Hibernate-Debugausgabe schaue, wird der Versionsvergleich durchgeführt ( delete from foo where id=? and version=?
), aber nicht mit dem erwarteten Effekt.
Was vermisse ich?
Aus der JPA-Spezifikation , Abschnitt 3.4.2 :
Eine Entität kann auf den Status ihres Versionsfelds oder ihrer Eigenschaft oder zugreifen Exportieren Sie eine Methode zur Verwendung durch die Anwendung, um auf die Version zuzugreifen, aber darf den Versionswert nicht ändern. Mit Ausnahme im Abschnitt bemerkt 4.10, nur der Persistenzanbieter darf den Wert des Versionsattributs im Objekt setzen oder aktualisieren.
Der Zweck der version -Eigenschaft besteht darin, uns vor gleichzeitigen Aktualisierungen zu schützen, die nach dem Laden des Objekts in den aktuellen Persistenzkontext auftreten können, und Hibernate implementiert es durch Ignorieren jedes von Ihnen manuell festgelegten Werts, sondern verwendet stattdessen den von Datenbank, wenn das Objekt geladen ist. Um dies zu überprüfen, aktivieren das Drucken gebundener Variablenwerte und Sie werden feststellen, dass der Wert aus der Datenbank verwendet wird.
Die Standardlösung, die in der Praxis bei der Arbeit mit DTOs verwendet wird, besteht beispielsweise darin, die Überprüfung manuell durchzuführen, wenn der Entitätsstatus von DTOs aktualisiert wird:
%Vor%Natürlich können Sie dies generischer machen, indem Sie von einer Basisklasse, die diese Überprüfung für alle versionsfähigen Entitäten bereitstellt, oder von einer util-Methode ausgehen. Einige Autoren tun dies zum Beispiel direkt im Versionsetter:
%Vor% Hibernate führt diese Überprüfung automatisch für getrennte Entitäten durch, wie in der Implementierung von DefaultMergeEventListener
:
Laut der JPA-Spezifikation (Abschnitt 11.1.54
, Hervorhebung von mir):
Die Annotation
Version
gibt das Versionsfeld oder die Eigenschaft einer Entitätsklasse an, die als optimistischer Sperrwert dient. Die Version wird verwendet, um die Integrität sicherzustellen, wenn die Zusammenführungsoperation und die optimistische Steuerung der gemeinsamen Zugriffe ausgeführt werden.
Beim Ausführen der Repository-Operation delete
für eine nicht verwaltete Instanz wird zuerst merge
ausgeführt, und daher wird ObjectOptimisticLockingFailureException
wie erwartet ausgegeben.
Das Ausführen der Repository-Operation delete
für eine verwaltete Instanz ruft jedoch direkt delete
für die zugrunde liegende EntityManager
auf, daher keine Ausnahme.
Zusammengefasst erfordert die Spezifikation, dass das @Version
-Feld von merge
verwendet wird, was für eine verwaltete Instanz nicht aufgerufen wird, daher im zweiten Fall kein Fehler.
Tags und Links java jpa spring-data-jpa hibernate