Веб-приложение использует Spring * OpenSessionInViewInterceptor
для открытия сеанса Hibernate для каждого запроса, закрывая его в конце обработки запроса. Это работает очень хорошо. Однако некоторые запросы, такие как загрузка файлов, могут длиться долго, оставляя сеанс открытым и связывая соединение с БД. В нашем случае копирование данных файла в поток вывода ответа - это последнее, что делает контроллер, и не требует сеанса Hibernate (данные файла считываются из файловой системы сервера). Эти запросы на загрузку файлов могут быстро занять большинство соединений в нашем пуле соединений с БД.
Я дал контроллеру ссылку на SessionFactory
и вызвал следующий метод непосредственно перед копированием данных файла в поток вывода ответа:
SessionFactoryUtils.closeSession(SessionFactoryUtils.getSession(sessionFactory, false));
OpenSessionInViewInterceptor
делает то же самое позже в процессе запроса, и закрытие сеанса кажется идемпотентным (то есть, вызов этого метода несколько раз имеет тот же эффект, что и вызов его один раз). Другими словами, локальное тестирование этого изменения прошло хорошо. Но это кажется немного опасным; если OpenSessionInViewInterceptor
или SessionFactoryUtils
изменится в более поздних версиях Spring, этот подход может быть неявным (возможно, утечка соединений?).
Конечная цель - закрыть соединение с базой данных перед началом отправки данных файла, и это один из способов достижения этого. Другим решением будет контроллер, помещающий входной поток в запрос как атрибут, и имеющий фильтр (стреляющий после OpenSessionInViewInterceptor
), который копирует данные входного потока в ответ. У этого есть свой собственный набор проблем (например, соответствующий код теперь разделен между контроллером и фильтром, а не централизован в контроллере).
Есть ли лучший способ справиться с этим?