понедельник, 26 мая 2014 г.

Hibernate: это должен помнить каждый - 3

В связи с выпиливанием из пакета org.springframework.orm.hibernate4 класса HibernateTemplate остро встал вопрос самостоятельного управления жизненным циклом сессии в наших приложениях. С этим возникают сложности. Давайте попробуем разобраться.

Как минимум, начиная с версии Hibernate 3.1, понятие "текущая сессия" привязано к границам текущей транзакции. Сессия открывается при первом вызове getCurrentSession() и закрывается при завершении транзакции. Так же содержимое сессии автоматически синхронизируется с БД (flush) перед коммитом транзакции. Вы можете вызывать метод getCurrentSession() в вашем коде столько раз, сколько нужно, но до тех пор пока транзакция не завершена.

Для включения данного режима необходимо выставить следующие настройки:

  • hibernate.transaction.manager_lookup_class - указать стратегию, специфичную для вашего сервера приложений;

  • hibernate.transaction.factory_class - в значение org.hibernate.transaction.JTATransactionFactory (org.hibernate.engine.transaction.internal.jta.JtaTransactionFactory для Hibernate 4)

Очень важно! Применение данных настроек не означает, что каждая сессия будет автоматически закрываться при завершении транзакции. Речь идет только о сессиях, полученных посредством getCurrentSession(). Если вы в своем коде используете openSession() и управляете сессией самостоятельно, то вам необходимо явно вызывать методы flush() и close().

При использовании управляемых контейнером транзакций (Container-Managed Transactions, CMT) - стандартной функциональности EJB - настройки несколько отличаются: значение свойства hibernate.transaction.factory_class нужно выставить в org.hibernate.transaction.CMTTransactionFactory (org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory для Hibernate 4).

Но что делать, если у нас нет сервера приложений?

Т.к. вне управляемого окружения, в отсутствие JTA, Hibernate не можете присоединить сессию к транзакции, он присоединяет ее к текущему потоку. При первом в потоке вызове getCurrentSession() будет создан специальный прокси-объект, не позволяющий сделать ничего, кроме как стартовать транзакцию. После старта транзакции в сессии возможно выполнение других операций. При завершении транзакции, неважно успешном или нет, текущая сессия автоматически закрывается. Следующий вызов getCurrentSession() снова создаст прокси и ситуация повторится. Таким образом Hibernate создает новые сессии, привязывает их к потокам, но на самом деле сессия имеет время жизни, совпадающее со временем жизни транзакции, т.е. полностью дублируется поведение в управляемом окружении.

Для включения данной стратегии необходимо выставить следующие настройки:

  • hibernate.transaction.factory_class - в значение org.hibernate.transaction.JDBCTransactionFactory (org.hibernate.engine.transaction.internal.jdbc.JdbcTransactionFactory для Hibernate 4);

  • hibernate.current_session_context_class - в значение thread.

Опять же, применение данных настроек не означает, что каждая сессия будет автоматически закрываться при завершении транзакции. Речь идет только о сессиях, полученных посредством getCurrentSession(). Если вы в своем коде используете openSession() и управляете сессией самостоятельно, то вам необходимо явно вызывать методы flush() и close().

Следует учитывать, что данная стратегия применима в Java SE, при использовании Java EE (по сути - при использовании EJB) нужно подключать JTA и привязывать сессию к транзакции.

Понравилось сообщение - подпишитесь на блог

Комментариев нет:

Отправить комментарий

Любой Ваш комментарий важен для меня, однако, помните, что действует предмодерация. Давайте уважать друг друга!