web-dev-qa-db-fra.com

Insertions par lots à l'aide de JPA EntityManager

Existe-t-il un moyen d'utiliser des insertions par lots à l'aide de JPA EntityManager. Je sais qu'il n'y a pas de moyen direct d'y parvenir, mais il doit y avoir un moyen de réaliser ce mécanisme.

En fait, pour chaque opération d'insertion, cela me prend 300 ms, ce que je veux réduire en utilisant des inserts par lots au lieu d'inserts simples.

Voici le code que j'utilise actuellement en cours d'exécution pour les insertions uniques

        @PersistenceContext(unitName = "testing")
        EntityManager eM;

        Query querys = this.eM.createNativeQuery(insertQuery);
        for (String s : someList) {
            //setting parameters
            querys.executeUpdate();
        }

Merci d'avance.

28
Ran

Il est possible d'effectuer des écritures par lots à l'aide de JPA, mais cela dépend fortement de l'implémentation spécifique de votre fournisseur de persistance, base de données et pilote JDBC. Par exemple, cette article explique comment activer l'écriture par lots (optimisation # 8) à l'aide d'EclipseLink JPA 2.3 et d'une base de données Oracle. Recherchez des paramètres de configuration similaires dans votre environnement particulier.

12
Óscar López

Selon que la transaction enferme la boucle, le traitement par lots se produit généralement déjà dans votre cas.

JPA va collecter toutes vos mises à jour dans son cache L1 et les écrit généralement dans la base de données dans un lot lorsque la transaction est validée. Ce n'est pas vraiment différent avec le traitement par lots dans JDBC, où chaque élément de lot que vous ajoutez est également temporairement en mémoire jusqu'à ce que vous appeliez une méthode de mise à jour.

Le problème potentiel est que vous n'avez pas de garanties solides que JPA effectue effectivement ce traitement par lots et si cela se produit lors de la transaction ou lorsqu'un seuil est atteint, mais j'ai trouvé cela dans la pratique dans presque tous les cas et en particulier dans les cas impliquant un tel boucle de mise à jour simple, il fait en effet du batching.

Un problème est que même si JPA effectue déjà le traitement par lots, vous pouvez toujours contrôler la taille des lots. Les articles liés par les autres réponses fournissent des informations assez utiles pour cela.

Enfin, vous devez savoir que votre cache L1 continue de croître en boucle, donc si le nombre de mises à jour est vraiment important, effacez-le périodiquement. Sinon, si votre logique métier peut la maintenir, effectuez des mises à jour partielles dans plusieurs transactions. Par exemple. poste 0 à 100 000 dans la transaction 1, 100,001 à 200 000 dans la transaction 2, etc.

23
Arjan Tijms

Je sais que c'est une question assez ancienne avec une réponse acceptée. Je souhaiterais néanmoins apporter une nouvelle réponse à ce sujet très spécifique "JPA batch inserts".

@PersistenceContext
private EntityManager entityManager;

@Value("${hibernate.jdbc.batch_size}")
private int batchSize;

public <T extends MyClass> Collection<T> bulkSave(Collection<T> entities) {
  final List<T> savedEntities = new ArrayList<T>(entities.size());
  int i = 0;
  for (T t : entities) {
    savedEntities.add(persistOrMerge(t));
    i++;
    if (i % batchSize == 0) {
      // Flush a batch of inserts and release memory.
      entityManager.flush();
      entityManager.clear();
    }
  }
  return savedEntities;
}

private <T extends MyClass> T persistOrMerge(T t) {
  if (t.getId() == null) {
    entityManager.persist(t);
    return t;
  } else {
    return entityManager.merge(t);
  }
}

Source: http://frightanic.com/software-development/jpa-batch-inserts/

17
Marcel Stör

JPA en lui-même n'a pas de paramètres pour le traitement par lots. Cependant, certains paramètres dépendent de l'implémentation. Voici un exemple d'hibernation .

3