Comment diffuser les résultats de Hibernate / JPA et des ressources de libération comme traitement?

boisson alcoolisée:

J'utilise des données Spring, JPA et Hibernate pour exécuter une fonction sur chaque enregistrement supérieur à un ID donné.

Voici mon DAO:

public interface MyEntityDao extends JpaRepository<MyEntity, Long>, {

    @QueryHints(value = @QueryHint(name = org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE, value = "1000"))
    Stream<MyEntity> findByIdGreaterThanOrderByIdAsc(Long id);
}

La méthode est utilisée comme ceci, et cela fonctionne:

@Transactional(readOnly = true)
public void printRecordsGreaterThan(Long lastId) {
    myEntityDao.findByIdGreaterThanOrderByIdAsc(lastId).forEach((entity) -> {
        System.out.println("entity: " entity.getId());
    });
}

La question est quand cette opération doit balayer une très large gamme. Je surveillais avec VisualVM et il est maintenant tous les enregistrements en mémoire (dizaines de valeur Go de RAM).

Est-il possible d'avoir ce code libérer les ressources une fois qu'ils sont traités plutôt que de garder en mémoire les?

Merci d'avance!

Solution

Merci à @julodnik dans les commentaires, invoquant clear()le gestionnaire d'entités si souvent résolu tous la question.

@PersistenceContext
private EntityManager em;

@Transactional(readOnly = true)
public void printRecordsGreaterThan(Long lastId) {
    AtomicLong counter = new AtomicLong();
    myEntityDao.findByIdGreaterThanOrderByIdAsc(lastId).forEach((entity) -> {
        long count = counter.getAndIncrement();
        if (count % 1000 == 0) {
            logger.info(String.format("Clearing %s session for result %d",  type.toString(), counter.get()));   
            em.clear();
        }
        System.out.println("entity: " entity.getId());
    });
}
julodnik:

Vous pouvez utiliser setFirstResult et setMaxResults pour itérer sur une grande ResultSet. Vous pouvez trouver un exemple dans cette question connexe .

Une autre question qui me vient à l'esprit est que vous pourriez avoir aggressif défini par défaut. Cela signifie que vous obtiennent peut-être toutes les entités liées et si elles ont des entités apparentées, ils seront récupérés aussi bien. Vous devez activer les instructions SQL dans votre fichier journal pour vérifier si cela se produit.

--- EDIT pour répondre à ce commentaire

Si les objets ne sont pas référencés dans Java, vous pouvez effacer le cache de premier niveau avec chasse d'eau et effacer (en entitymanager). Cela devrait effacer tous les objets chargés.

Je suppose que tu aimes

Origine http://43.154.161.224:23101/article/api/json?id=331697&siteId=1
conseillé
Classement