В Spring с jpa/hibernate, как сохранить сеанс открытым, чтобы избежать отложенных исключений инициализации?

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

Если я вместо этого оставлю коллекцию как отложенную загрузку, как мне сохранить сеанс открытым? Я думал о попытке @Transactional, но даже если бы это сработало, я бы не хотел этого делать, потому что было бы неправильно оставлять транзакцию открытой в течение длительного метода.

6 ответов

Решение

https://www.hibernate.org/43.html

По сути, у вас есть несколько вариантов.

-Вы можете использовать шаблон "открыть сеанс в представлении", где вы используете логику в стиле фильтра / перехватчика /AOP, чтобы открыть сеанс, когда начинается логика на стороне сервера, и закрыть его, когда он закончится.

-Вы могли бы осуществлять диалоги, охватывающие несколько циклов запрос-ответ.

Простой старый Servlet Filter - самый простой.

Последний вариант, который, по-видимому, был пропущен, состоит в том, что вы можете построить свой объектный граф на основе своего варианта использования с помощью JOIN.

Это приведет к инициализации объекта, т.е. он не будет прокси.

Используйте этот подход, если вы контролируете клиента (т.е. вы не создаете открытую службу, публикующую API-интерфейс), потому что вам нужно знать, к какому состоянию обращаются при закрытии сеанса, поскольку транзакция закрыта.

Как уже говорили другие, вам следует ознакомиться с шаблоном "открыть сеанс в представлении", основная идея которого заключается в том, чтобы открыть сеанс гибернации в течение всей продолжительности обработки http-запроса. Существуют как спящие, так и пружинные решения - я использовал Spring раньше, и он отлично работает.

В вопросе вы упоминаете, что не хотите, чтобы транзакция была открыта в течение длительного времени. Для большинства людей это не проблема, потому что каждый запрос обрабатывается относительно быстро. Однако, если в вашем случае это действительно невозможно, этот шаблон не будет работать для вас. Можете ли вы объяснить, почему вы не хотите, чтобы транзакции оставались открытыми?

Используете ли вы Spring HibernateTemplate? Я думаю, он будет управлять сессией. В качестве альтернативы, если вы используете Hibernate 3.0.1 или выше, Spring все равно сможет управлять сессией за вас.

Есть запись в блоге SpringSource, которая описывает, как это настроить. Я включил выдержку ниже:

Начиная с Hibernate 3.0.1 (и в Java Persistence API с момента его первого выпуска) у Spring появилась возможность управлять базовым ресурсом без необходимости просматривать какой-либо из шаблонов, доступных для этих технологий. Это означает, что даже если вы используете Hibernate API напрямую (например, через SessionFactory.getCurrentSession()), вы все равно будете использовать Spring Hibernate Session. То же самое относится к EntityManager, полученному через JPA EntityManagerFactory. Это еще одна причина, по которой вам больше не нужно использовать Spring HibernateTemplate для получения интегрированного опыта. [...]

Ниже приведен XML-код, который мы будем использовать для сборки приложения. Как вы можете видеть, мы, конечно, по-прежнему используем Spring для настройки Hibernate (используя LocalSessionFactoryBean).

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <!– the works –>
</bean>
<bean id="accountRepo" class="com.mycompany.HibernateAccountRepository">
  <constructor-arg ref="sessionFactory"/>
</bean>

Теперь, как я уже говорил, из-за небольшого изменения в Hibernate 3.0.1 Spring может управлять сессией Hibernate за вас, без необходимости проходить сессию Hibernate. Единственное, чего не хватало, был перевод исключения. Для этого вам также нужно аннотировать репозиторий с помощью аннотации @Repository (предоставленной Spring) и включать преобразование исключений с помощью постпроцессора.

@Repository // from org.springframework.stereotype
public class HibernateAccountRepository implements AccountRepository {
    // see above for full impl…
}

Сейчас я не использовал Spring, но я использовал Hibernate в нескольких разных проектах. Подход, который я выбрал для самого последнего проекта, вырос из паттерна Обработка защитных сессий (в сочетании с фильтром сервлетов), и мы довольны им. Вы можете найти больше шаблонов дизайна здесь.

Когда вы оставляете сеанс открытым, который прочитал некоторые данные, вы оставляете эту транзакцию открытой. Длительные транзакции не являются большой проблемой (хотя это может зависеть от вашей базы данных), что действительно вызывает проблемы, так как блокировки удерживаются в течение длительного времени, но они могут быть созданы только после того, как вы действительно измените данные в базе данных. Опять же, это зависит от вашей базы данных.

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