Почему важно явно закрывать Stream, полученный из JPA репозитория?

«Почему важно явно закрывать Stream, полученный из JPA репозитория?» — вопрос из категории Hibernate, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Stream, возвращаемый JPA-репозиторием (например, через метод, помеченный @Query), привязан к активным ресурсам базы данных. Его необходимо закрывать для:

  • Освобождения соединения с БД: Stream может удерживать JDBC-соединение из пула.
  • Закрытия курсора: При ленивой потоковой обработке больших результатов СУБД открывает курсор, который потребляет память на стороне сервера БД.

Незакрытый Stream приводит к утечкам ресурсов, исчерпанию пула соединений и потенциальной блокировке операций.

Правильный подход с try-with-resources:

try (Stream<Employee> employeeStream = 
        employeeRepository.streamAllByDepartment("Engineering")) {
    // Обработка в памяти
    List<String> names = employeeStream
                          .map(Employee::getName)
                          .collect(Collectors.toList());
} // Stream, а вместе с ним курсор и соединение, будут закрыты здесь автоматически

Важно: Работа со Stream в JPA обычно должна выполняться в пределах активной транзакции (@Transactional), так как для загрузки каждой следующей записи может потребоваться доступ к БД.