Метод репозитория Spring, который возвращает поток Java 8, не закрывает соединение JDBC

У меня есть репозиторий Spring data:

@Repository
interface SomeRepository extends CrudRepository<Entity, Long> {
    Stream<Entity> streamBySmth(String userId);
}

Я вызываю этот метод в каком-то компоненте Spring:

@Scheduled(fixedRate = 10000)
private void someMethod(){
    someRepository.streamBySmth("smth").forEach(this::callSomeMethod);
}

Я использую базу данных MySQL. И когда я запускаю приложение после некоторых успешных вызовов метода, оно выдает исключение:

o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 0, SQLState: 08001
o.h.engine.jdbc.spi.SqlExceptionHelper   : Could not create connection to database server.
o.s.s.s.TaskUtils$LoggingErrorHandler    : Unexpected error occurred in scheduled task.

org.springframework.dao.DataAccessResourceFailureException: Unable to acquire JDBC Connection; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection

Кажется, это соединение не было правильно закрыто Spring. Если я изменил возвращаемое значение метода на List с Stream, он работает правильно.

ОБНОВЛЕНИЕ: версия Spring Boot — 1.4.1.RELEASE.


person Eduard Grinchenko    schedule 07.12.2016    source источник
comment
Вы пытались вызвать close в потоке?   -  person marstran    schedule 07.12.2016
comment
Я пробовал, не помогло. Тем не менее, закрывать Stream вручную неправильно.   -  person Eduard Grinchenko    schedule 07.12.2016
comment
Я не очень хорошо знаком с возвратом Stream из репозитория, но Stream ленив, так как иначе Spring узнает, когда закрыть соединение? Stream также является AutoClosable, поэтому вы можете использовать его в предложении try-with-resources.   -  person marstran    schedule 07.12.2016
comment
Streams имеет завершающие операции, а это значит, что после них вы больше ничего не можете делать со Stream. forEach — одна из таких операций.   -  person Eduard Grinchenko    schedule 07.12.2016
comment
У них есть завершающие операции, но это не закрывает поток. См. здесь: stackoverflow.com/questions/37659872/   -  person marstran    schedule 07.12.2016


Ответы (2)


Как четко указано в справочной документации, Streams необходимо использовать с блоком try-with-resources.

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

@Transactional
public void someMethod() {

  try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {
    stream.forEach(…);
  } 
}
person Oliver Drotbohm    schedule 07.12.2016
comment
Это выглядит разумно, но это не помогает нам. У меня все еще такая же ошибка после нескольких запросов. - person Eduard Grinchenko; 08.12.2016
comment
К сожалению, опять не помогает. Я пытался использовать @Transactional(readOnly = true), а также пытался использовать .close() потоки. Теперь он успешно проходит 100 отсчетов и терпит неудачу. Насколько я понимаю, это означает, что новое соединение открывается при каждом запросе. Может ли это быть ошибкой Spring? - person Eduard Grinchenko; 09.12.2016
comment
Можете ли вы предоставить образец, воспроизводящий вашу проблему? В заявке описана проблема, которая звучит как здесь, но ее можно решить, выполнив следующие действия. то, что я описал выше. - person Oliver Drotbohm; 09.12.2016

Использование @Transactional(readOnly = true) и модификатора общего доступа решит проблему. Любой другой модификатор доступа не будет работать.

person user666    schedule 04.04.2019