8 Stimmen

Hibernate + "ON DUPLICATE KEY"-Logik

Ich suche nach einem Weg, um speichern oder aktualisieren Datensätze, entsprechend dem eindeutigen Schlüssel der Tabelle, der sich aus mehreren Spalten zusammensetzt).

Ich möchte die gleiche Funktionalität erreichen, die von INSERT ... ON DUPLICATE KEY UPDATE - d.h. blindes Speichern eines Datensatzes und Einfügen eines neuen Datensatzes durch die DB/Hibernate bzw. Aktualisieren des vorhandenen Datensatzes, wenn der eindeutige Schlüssel bereits existiert.

Ich weiß, ich kann die @SQLInsert( sql="INSERT INTO .. ON DUPLICATE KEY UPDATE") aber ich hatte gehofft, dass ich keine eigenen SQLs schreiben und Hibernate die Arbeit erledigen lassen müsste. (Ich nehme an, dass es eine bessere Arbeit leisten wird - warum sonst Hibernate verwenden?)

3voto

rghome Punkte 7901

Hibernate wirft möglicherweise eine ConstraintViolationException wenn Sie versuchen, eine Zeile einzufügen, die eine Einschränkung verletzt (einschließlich einer eindeutigen Einschränkung). Wenn Sie diese Ausnahme nicht erhalten, kann es sein, dass Sie eine andere allgemeine Hibernate-Ausnahme erhalten. Dies hängt von der Version von Hibernate und der Fähigkeit von Hibernate ab, die MySQL-Ausnahme auf eine Hibernate-Ausnahme in der von Ihnen verwendeten Version und dem Datenbanktyp abzubilden (ich habe es nicht mit allen getestet).

Sie erhalten die Ausnahme nur nach dem Aufruf von flush() Sie sollten also sicherstellen, dass dies auch in Ihrem try-catch-Block enthalten ist.

Ich würde vorsichtig sein, Lösungen zu implementieren, bei denen man zuerst prüft, ob die Zeile existiert. Wenn mehrere Sitzungen die Tabelle gleichzeitig aktualisieren, könnte es zu einer Race Condition kommen. Zwei Prozesse lesen die Zeile fast zur gleichen Zeit, um zu sehen, ob sie existiert; beide stellen fest, dass sie nicht vorhanden ist, und versuchen dann, eine neue Zeile zu erstellen. Je nachdem, wer das Rennen gewinnt, wird einer von ihnen scheitern.

Eine bessere Lösung ist es, zuerst das Einfügen zu versuchen, und wenn es fehlschlägt, anzunehmen, dass es bereits vorhanden war. Sobald jedoch eine Ausnahme auftritt, müssen Sie einen Rollback durchführen, so dass Sie diesen Ansatz nur begrenzt anwenden können.

0voto

Stijn Geukens Punkte 15139

Das klingt für mich nicht gerade nach einem sauberen Ansatz. Es wäre besser, zunächst zu prüfen, ob eine Entität mit dem/den angegebenen Schlüssel(n) existiert. Wenn ja, aktualisieren Sie sie und speichern Sie sie, wenn nicht, erstellen Sie eine neue Entität.

EDIT

Oder überlegen Sie, ob merge() das ist, wonach Sie suchen:

  • wenn es eine persistente Instanz mit dem gleichen Bezeichner gibt, die derzeit mit der Sitzung verbunden ist, kopiere den Zustand des gegebenen Objekts auf die persistente Instanz
  • wenn der Sitzung derzeit keine dauerhafte Instanz zugeordnet ist, versuchen Sie, sie aus der Datenbank zu laden, oder erstellen Sie eine neue dauerhafte Instanz
  • die dauerhafte Instanz wird zurückgegeben
  • die gegebene Instanz wird nicht mit der Sitzung verbunden, sie bleibt losgelöst

< http://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html

-3voto

Raman Punkte 1417

Sie könnten saveOrUpdate() aus der Klasse Session verwenden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X