Spring Data JPA: Lösche optimistische Sperrsemantik

8

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:

%Vor%

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:

durchgeführt %Vor%

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?

    
aha 04.05.2017, 09:41
quelle

2 Antworten

6

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 :

%Vor%     
Dragan Bozanovic 06.05.2017, 13:13
quelle
5

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.

    
manish 06.05.2017 12:47
quelle