Я использую Spring Data, JPA и Hibernate для выполнения функции над каждой записью, превышающей заданный ID.
Вот мой 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);
}
Метод используетсявот так, и это работает:
@Transactional(readOnly = true)
public void printRecordsGreaterThan(Long lastId) {
myEntityDao.findByIdGreaterThanOrderByIdAsc(lastId).forEach((entity) -> {
System.out.println("entity: " entity.getId());
});
}
Проблема в том, когда этой операции нужно сканировать очень большой диапазон. Я контролировал его с помощью VisualVM, и он хранит все записи в памяти (ОЗУ в десятках гигабайт).
Есть ли способ заставить этот код освобождать ресурсы после их обработки, а не хранить их в памяти?
Заранее спасибо!
Решение
Благодаря @julodnik в комментариях вызывается clear()
в менеджере сущностей, который так часто решаетсявопрос.
@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());
});
}