2014-12-31 12 views
6

Meine Entität hat sowohl automatisch generierten Primärschlüssel (ID) als auch Geschäftsschlüssel (Namespace). Ich muss den Datensatz aktualisieren, indem ich den alten ersetze. Also, ich suche es nach Geschäftsschlüssel, lösche es und speichere eine neue Entität. Dies funktioniert, wenn jede Operation in ihrer eigenen Transaktion ausgeführt wird. Aber sobald ich alle in die gleiche Transaktion eingetragen habe, wurde delete() bis zur Ausführung von save() noch nicht ausgeführt, daher erhalte ich eine Constraint-Verletzung.Spring JpaRepository: delete() mit anschließendem save() in derselben Transaktion

transactionTemplate.execute(status -> { 
    MyEntity oldEntity = repository.findByNamespace(namespace); 
    if (oldEntity != null) { 
     repository.delete(oldEntity); 
    } 
    repository.save(newEntity); 
    return null; 
}); 

ich es tatsächlich geschafft, es zu umgehen, indem

repository.flush(); 

Zugabe Aber ich wirklich nicht bekommen, warum ich diese flush() brauchen.

+1

Ich denke, das ist, weil der JPA-Anbieter frei zu reorganisieren und/oder optimieren die Datenbank schreibt die ausstehenden Änderungen aus dem persistenten Kontext, insbesondere der JPA-Anbieter fühlt sich nicht verpflichtet, die Datenbank schreibt in der Reihenfolge und Form durchzuführen durch die individuellen Veränderungen des persistenten Kontextes impliziert. Jedenfalls ist die beschriebene Situation bekannt und die flush() ist eine bekannte Problemumgehung. – Michal

Antwort

4

Weil repository.flush() die Änderungen in der Datenbank löscht, indem sie EntityManager.flush() aufruft. Wenn Sie also die Änderungen nach delete() löschen, wird sql ausgeführt und die folgende Speicherung hat keine Probleme.

Wenn Sie keinen Flush aufrufen, muss der Persistenzanbieter bestimmen, wann die Änderungen zu spülen sind, wobei die Transaktionsfestschreibung die Frist ist. Auch Provider spülen Änderungen nicht in einer bestimmten Reihenfolge, so dass es manchmal vorkommen kann, dass Ihr Vorgang erfolgreich ist und manchmal nicht. Normalerweise wartet Provider, bis die Zeit bündig begehen, aber Sie können das beeinflussen, indem sie einen Flush-Modus einstellen:

for entitymanager 
EntityManager.setFlushMode(FlushModeType type); 

or for query 
Query.setFlushMode(FlushModeType type); 

Es gibt eine entsprechende Einstellung in Spring Daten JPA auch, ich bin sicher, aber ich weiß nicht genau wissen, welcher es ist.

Beachten Sie jedoch, dass das sofortige Löschen der Änderungen die Leistung verringert, daher sollten Sie bei der Verwendung vorsichtig sein. In Ihrem speziellen Fall ist es besser, die Entität zu aktualisieren, als sie zu löschen und dann die neue Entität mit demselben Geschäftsschlüssel beizubehalten.

Verwandte Themen