2017-07-12 2 views
1

Ich arbeite an einer Spring Boot-Anwendung, die JPA (Hibernate) für die Persistenzschicht verwendet.Bulk Einfügen vorhandener Daten: Verhindern, dass JPA vor jedem Einfügen eine Auswahl trifft

Ich implementiere derzeit eine Migrationsfunktionalität. Wir deponieren grundsätzlich alle vorhandenen Entitäten des Systems in eine XML-Datei. Dieser Export enthält auch IDs der Entitäten.

Das Problem, das ich habe, befindet sich auf der anderen Seite, Reimportieren der vorhandenen Daten. In diesem Schritt wird das XML erneut in ein Java-Objekt umgewandelt und in der Datenbank gespeichert.

Beim Versuch, die Entität zu speichern, verwende ich die merge Methode der EntityManager Klasse, die funktioniert: alles wird erfolgreich gespeichert.

Wenn ich jedoch die Abfrageprotokollierung von Hibernate aktiviere, sehe ich, dass vor jeder Einfügeabfrage eine Auswahlabfrage ausgeführt wird, um festzustellen, ob eine Entität mit dieser ID bereits existiert. Dies liegt daran, dass die Entität bereits eine von mir angegebene ID hat.

Ich verstehe dieses Verhalten und es macht tatsächlich Sinn. Ich bin mir aber sicher, dass die IDs nicht existieren werden, so dass die Auswahl für meinen Fall keinen Sinn ergibt. Ich speichere Tausende von Datensätzen, so dass Tausende von Select-Abfragen für große Tabellen erforderlich sind, was den Importprozess drastisch verlangsamt.

Meine Frage: Gibt es eine Möglichkeit, dies zu ändern "zu überprüfen, ob eine Entität existiert vor dem Einfügen" aus?


Zusätzliche Informationen:

Wenn ich entityManager.persist() statt Druck verwenden, erhalte ich diese Ausnahme:

org.hibernate.PersistentObjectException: freistehende Einheit geben bestehen

Um eine mitgelieferte/bereitgestellte ID verwenden zu können, verwende ich diesen ID-Generator:

@Id 
@GeneratedValue(generator = "use-id-or-generate") 
@GenericGenerator(name = "use-id-or-generate", strategy = "be.stackoverflowexample.core.domain.UseIdOrGenerate") 
@JsonIgnore 
private String id; 

Der Generator selbst:

public class UseIdOrGenerate extends UUIDGenerator { 

    private String entityName; 

    @Override 
    public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException { 
     entityName = params.getProperty(ENTITY_NAME); 
     super.configure(type, params, serviceRegistry); 
    } 

    @Override 
    public Serializable generate(SessionImplementor session, Object object) 
    { 
     Serializable id = session 
      .getEntityPersister(entityName, object) 
      .getIdentifier(object, session); 

     if (id == null) { 
     return super.generate(session, object); 
     } else { 
     return id; 
     } 
    } 
} 

Antwort

1

Wenn Sie sicher sind, dass Sie nie in der Datenbank alle vorhandenen Eintrag aktualisieren werden und alle Unternehmen sollten immer frisch eingeführt werden, dann würde ich für unterwegs persist Operation anstelle von merge.

Per Update

In diesem Fall (ID-Feld Set-up wird als automatisch generiert) der einzige Weg, um die Erzeugung Anmerkungen aus dem ID-Feld entfernen würde und lassen Sie die Konfiguration wie:

@Id 
@JsonIgnore 
private String id; 

Also im Grunde Einstellung der ID für immer manuell zugewiesen werden. Dann wird der Persistenzanbieter Ihre Entität als transient betrachten, selbst wenn die ID vorhanden ist. Dies bedeutet, dass persist funktionieren würde und keine zusätzlichen Selects generiert würden.

+0

Danke, das habe ich vergessen zu erwähnen. Ich habe versucht, persist zu verwenden, aber es löst eine Ausnahme aus. Ich habe meinen ursprünglichen Beitrag mit den Details aktualisiert. – geoffreydv

+0

Wenn Sie in der Lage sind, Änderungen vorzunehmen, überprüfen Sie meine upadte –

+0

Das ist eine gute Idee, aber wenn ich richtig verstehe, würde dies Einfügen neuer Elemente in allen anderen Teilen der Anwendung brechen, weil die IDs leer sein wird. Ich müsste überall manuell eine setId (generateId()) machen, was momentan keine Option ist. – geoffreydv

0

Ich bin mir nicht sicher, ob ich die ID ausfüllen oder nicht.Wenn Sie es auf der Anwendungsseite füllen, überprüfen Sie die answer here. Ich kopierte es unter:

Hier ist der Code of Spring SimpleJpaRepository Sie mithilfe von Spring Data Repository verwenden:

@Transactional 
public <S extends T> S save(S entity) { 

    if (entityInformation.isNew(entity)) { 
     em.persist(entity); 
     return entity; 
    } else { 
     return em.merge(entity); 
    } 
} 

Es ist folgendes:

standardmäßig Spring Data JPA die inspiziert Bezeichnereigenschaft der gegebenen Entität Wenn die Bezeichnereigenschaft null ist, wird die Entität als neu angenommen, andernfalls als nicht neu.

Link to Spring Data documentation

Und so, wenn einer Ihrer Einheit ein ID-Feld nicht null hat, wird Frühling Hibernate auszukommen ein Update (und so SELECT a vor).

Sie können dieses Verhalten auf zwei Arten überschreiben, die in der gleichen Dokumentation aufgeführt sind. Ein einfacher Weg ist es, dass Ihre Entity Persistable (statt Serializable) implementiert, wodurch Sie die Methode "isNew" implementieren.

Verwandte Themen