web-dev-qa-db-fra.com

Comment puis-je empêcher les données de printemps JPA de faire un SELECT avant un save ()?

Nous écrivons une nouvelle application par rapport à une base de données existante. J'utilise Spring Data JPA et je fais simplement 

MyRepository.save() 

sur ma nouvelle entité, en utilisant 

MyRepository extends CrudRepository<MyThing, String>

J'ai remarqué dans les journaux que l'hibernation effectue une sélection avant l'insertion et qu'elle prend beaucoup de temps, même lorsque vous utilisez les index. 

J'ai cherché ceci, et les réponses que j'ai trouvées sont généralement liées à Hibernate en particulier. Je suis assez nouveau dans JPA et il semble que JPA et Hibernate soient assez étroitement liés, du moins lorsqu’on l’utilise dans le contexte de Spring Data. Les réponses liées suggèrent d'utiliser Hibernate persist () ou, d'une manière ou d'une autre, une session, éventuellement à partir d'un entityManager? Je n'ai rien eu à faire avec des sessions ou des entityManagers, ou directement avec une API Hibernate. Jusqu'à présent, j'ai effectué des insertions simples avec save () et un couple de @Query dans mes dépôts.

7
user26270

Voici le code de Spring SimpleJpaRepository que vous utilisez à l'aide du référentiel Spring Data:

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

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

Il fait ce qui suit:

Par défaut, Spring Data JPA inspecte la propriété d'identifiant de l'entité donnée. Si la propriété identifiant est null, l'entité sera considérée comme nouvelle, sinon non nouvelle.

Lien vers la documentation Spring Data

Et donc, si l’une de vos entités a un champ d’identification non nul, Spring fera effectuer à Hibernate une mise à jour (et donc un SELECT auparavant).

Vous pouvez remplacer ce comportement par les deux manières énumérées dans la même documentation. Un moyen simple consiste à rendre vos implémentations d'entité persistantes (au lieu de sérialisables), ce qui vous obligera à implémenter la méthode "isNew".

11
Bertrand88

Si vous fournissez votre propre valeur d'identifiant, Spring Data supposera que vous devez rechercher une clé en double dans la base de données (d'où le paramètre select + insert).

La meilleure pratique consiste à utiliser un générateur d'identifiant, comme ceci:

@Entity
public class MyThing {
    @Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "uuid2")
    private UUID id;
}

Si vous devez réellement insérer votre propre identifiant et que vous souhaitez empêcher la sélection + insertion, implémentez Persistable, par exemple.

@Entity
public class MyThing implements Persistable<UUID> {

    @Id
    private UUID id;

    @Override
    public UUID getId() {
        return id;
    }

    //prevent Spring Data doing a select-before-insert - this particular entity is never updated
    @Override
    public boolean isNew() {
        return true;
    }
}
2
Paul Hilliar