Es scheint, als würde es oft kommen, aber ich habe ohne Erfolg gegoogelt.
Angenommen, Sie haben eine Hibernate-Entität User
. Sie haben eine User
in Ihrem DB mit der ID 1.
Sie haben zwei laufende Threads, A und B. Sie tun Folgendes:
close
s ist Session
delete
s it Session
und merge
s Benutzer 1 All meine Tests zeigen an, dass merge
versucht, Benutzer 1 in der DB zu finden (das kann natürlich nicht), also fügt er einen neuen Benutzer mit der ID 2 ein.
Meine Erwartung wäre andererseits, dass Hibernate sehen würde, dass der Benutzer, der zusammengeführt wird, nicht neu ist (weil er eine ID hat). Es würde versuchen, den Benutzer in der DB zu finden, was fehlschlagen würde, also würde es keine Einfügung oder ein Update versuchen. Idealerweise würde es irgendeine Art von Gleichzeitigkeitsausnahme auslösen.
Beachten Sie, dass ich optimistisches Sperren über @Version
verwende, und das hilft nicht weiter.
Also, Fragen:
merge
in einem JPA EntityManager
anstelle eines Hibernate Session
? Ich habe JSR-220 betrachtet, von dem Session#merge
beansprucht, seine Semantik zu erhalten . Der JSR ist leider mehrdeutig, habe ich gefunden.
Es heißt:
Optimistisches Sperren ist eine Technik, die verwendet wird, um diese Aktualisierungen sicherzustellen Zu der Datenbank werden Daten, die dem Zustand einer Entität entsprechen, gemacht nur wenn keine intervenierende Transaktion diese Daten seit der Aktualisierung aktualisiert hat Entitätsstatus wurde gelesen.
Wenn Sie "Aktualisierungen" nehmen, um allgemeine Mutationen der Datenbankdaten, einschließlich Löschungen, und nicht nur ein SQL UPDATE
, was ich tue, zu beachten, können Sie argumentieren, dass das beobachtete Verhalten nicht mit optimistisch übereinstimmt Sperren.
Viele Leute stimmen zu, angesichts der Kommentare zu meiner Frage und der darauffolgenden Entdeckung von diesem Fehler .
> Aus rein praktischer Sicht könnte das Verhalten, ob konform oder nicht, zu einigen Fehlern führen, weil es den Erwartungen vieler Entwickler widerspricht. Es scheint keine einfache Lösung dafür zu geben. In der Tat scheint Spring Data JPA dieses Problem vollständig zu ignorieren, indem man blindlings using EM#merge
. Möglicherweise gehen andere JPA-Anbieter anders damit um, aber mit Hibernate könnte dies zu Problemen führen.
Ich arbeite derzeit daran, indem ich derzeit Session#update
verwende. Es ist wirklich hässlich und erfordert Code, um den Fall zu behandeln, wenn Sie versuchen, update
eine Entität losgelöst zu machen, und es gibt bereits eine verwaltete Kopie davon. Aber es wird auch nicht zu falschen Inserts führen.
Bitte lesen Sie den Text aus der Winterschlaf-Dokumentation.
Kopieren Sie den Status des angegebenen Objekts auf das persistente Objekt mit demselben Bezeichner. Wenn der Sitzung derzeit keine persistente Instanz zugeordnet ist, wird sie geladen. Gibt die persistente Instanz zurück. Wenn die angegebene Instanz nicht gespeichert ist, speichern Sie eine Kopie von und geben Sie sie als neu persistente Instanz zurück.
Es wurde klar gesagt, dass der Zustand (Daten) des Objekts in der Datenbank kopiert werden soll. Wenn das Objekt nicht vorhanden ist, speichern Sie eine Kopie dieser Daten. Wenn wir sagen, speichern Sie eine Kopie Hibernate immer einen Datensatz mit neuer Kennung erstellen.
Die Hibernate-Merge-Funktion funktioniert etwa folgendermaßen:
Die Sperre wird immer auf verbundene Entitäten angewendet. Wenn die Entity getrennt ist, wird sie immer im Ruhezustand geladen und der Versionswert wird aktualisiert.
Sperren wird verwendet, um Nebenläufigkeitsprobleme zu kontrollieren. Es ist nicht das Problem der Parallelität.
1. Ist mein beobachtetes Hibernate-Verhalten das beabsichtigte Verhalten?
Das Verhalten ist korrekt. Sie versuchen nur Operationen auszuführen, die nicht gegen gleichzeitige Datenänderungen geschützt sind. Wenn Sie die Operation in zwei Sitzungen aufteilen müssen. Suchen Sie einfach das Objekt für die Aktualisierung erneut und prüfen Sie, ob es noch da ist, werfen Sie die Ausnahme, wenn nicht. Wenn es einen gibt, sperren Sie es mit em. (Klasse, Primärschlüssel, LockModeType); oder verwenden Sie @Version oder @Entity (optimisticLock = OptimisticLockType.ALL / DIRTY / VERSION), um das Objekt bis zum Ende der Transaktion zu schützen.
2.Wie lautet das Verhalten beim Aufruf von Merge auf einem JPA-EntityManager anstelle einer Hibernate-Sitzung?
Wahrscheinlich: ja
3.Wenn die Antwort auf 2. ja ist, warum beschwert sich niemand darüber?
Wenn Sie Ihre Operationen mit pessimistischen oder optimistischen Sperren schützen, verschwindet das Problem:)
Das Problem, das Sie lösen möchten, heißt: Nicht wiederholbares Lesen
Tags und Links java jpa hibernate concurrency