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

Другие вопросы по тегам