Hibernate Cache1 OutOfMemory с OpenSessionInView
У меня есть сущность "Автомобиль" с DTO "Автомобиль".
я использую OpenSessionInView
с полосами.
В моем бине действия Stripes мне нужно сгенерировать CSV, содержащий данные для около 50000 транспортных средств.
Таким образом, как мне сказал разработчик Stripes, я записываю файл в outputtream следующим способом:
StreamingResolution() {...}.stream(HttpServletResponse)
У меня есть служба, которая берет некоторую информацию о нумерации страниц, загружает часть автомобилей и превращает их в DTO.
Эти dto возвращаются в представление и записываются в csv.
Система разбиения на страницы (500 элементов для каждой страницы) была создана, чтобы избежать списка 50000 DTO и иметь некоторые проблемы с памятью.
Но это еще не работает идеально. С помощью Jmap я увидел, что в конце процесса CSV в кучу загружено более 40000 автомобилей, а не мусора.
С профайлером Yourkit мне кажется, что эти сущности все еще находятся в кеше L1 hibernate (ссылка на StatefulPersistenceContext
) и так как у меня есть OpenSessionInView
, я думаю, проблема в том, что разговор немного длинный, и кэш нужно очистить...
Мне просто интересно, как это сделать элегантно, так как мои методы дао, загружающие транспортные средства, используются многими службами, которым не требуется сеанс очистки / очистки.
Кто-то знает, что я мог сделать? Я думаю, я могу сделать метод в DAO/Service, чтобы очистить сессию, но это не очень элегантно...
Это довольно большой проект, и я очень просто его описал. Пожалуйста, не говорите мне не использовать opensessioninview или что-то подобное, это не мое решение...;)
3 ответа
Это может быть не элегантно, но в подобных случаях исключение сущностей из сессии является единственным практическим решением.
Например, когда вы закончите записывать данные объекта в выходной поток, вызовите session.evict(entity)
удалить его из кэша сеанса. В качестве альтернативы, назовите это в конце каждой "страницы".
Сочетание механизма подкачки и удаления должно гарантировать, что в кеше никогда не будет более 500 объектов.
Выселение объектов - это элегантно, и это единственное хорошее решение для создания отчетов, экспорта в CSV и т. Д.
Лучший изящный способ - внедрить его внутри службы, которая откроет итератор, выселит каждый элемент после процесса. Класс будет предоставлен для вызова службы, который будет потребителем товара.
открытый интерфейс ItemConsumer {пустота потребления (Item item); }
public void processAllItems (потребитель ItemConsumer) {
.. делай свою работу }
Вы, вероятно, хотите явно открыть сеанс без сохранения состояния.
например
StatelessSession session = sessionFactory.openStatelessSession();
Из документов:
StatelessSession не имеет связанного с ним персистентного контекста и не предоставляет много семантики жизненного цикла более высокого уровня. В частности, сеанс без сохранения состояния не реализует кэш первого уровня и не взаимодействует ни с каким вторым уровнем или кешем запросов. Он не реализует транзакционную запись или автоматическую грязную проверку
Смотрите здесь для более подробной информации:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/batch.html