Спящий режим сеанса Hibernate [и Spring @Transactional]

Я использую Spring и Hibernate в веб-приложении,

SessionFactory вводится в DAO bean, а затем этот DAO используется в сервлете через webservicecontext.

Методы DAO являются транзакционными, внутри одного из методов, которые я использую... getCurrentSession(). save (myObject);

Один сервлет вызывает этот метод с переданным объектом.

Обновление, похоже, не очищается сразу, для просмотра изменений в базе данных требуется около 5 секунд. Метод сервлета, в котором вызывается этот метод обновления DAO, занимает до половины секунды.

После завершения метода @Transactional DAO промывка может не произойти? Это, похоже, не правило [я уже вижу это].

Тогда возникает вопрос: что делать, чтобы заставить сеанс стираться после каждого метода DAO? Это может быть не очень хорошо, но, говоря о слое службы, некоторые методы должны заканчиваться немедленным сбросом, а поведение сеанса Hibernate не предсказуемо.

Итак, что делать, чтобы гарантировать, что мой метод @Transactional сохраняет все изменения после последней строки этого кода метода?

 getCurrentSession().flush() is the only solution?

p.s. Я где-то читал, что @Transactional IS ASSOCIATED с транзакцией DB. Возврат метода, транзакция должна быть выполнена. Я этого не вижу.

Ответы

Ответ 1

После завершения метода @Transactional "верхнего уровня" (т.е. метода, вызванного из вашего сервлета), транзакция должна быть зафиксирована, а поведение по умолчанию Hibernate должно быть выполнено на фиксации.

Кажется, что что-то странное происходит, и вам нужно немного разобраться.

Исследуйте свои журналы, в частности, я установил уровень ведения журнала в DEBUG в вашем диспетчере транзакций, чтобы увидеть, что делает менеджер транзакций.

Кроме того, установите запись для спящего режима (установите show_sql в true): это будет выводиться в System.out, когда происходит промывка, и это может дать вам некоторые подсказки.

Отправляй отчет, если найдешь что-нибудь интересное.

Ответ 2

Amaze Я считаю, что этот вопрос является точным ответом, который может решить такую ​​точную ситуацию, вы можете использовать FlushMode.ALWAYS для конкретного DAO всякий раз, когда вам требуется полностью очистить сеанс после каждой транзакции.

@Autowired
private SessionFactory sessionFactory;

@Before
public void myInitMethod(){
  sessionFactory.getCurrentSession().setFlushMode(FlushMode.ALWAYS);
}

ALWAYS flushmode не предпочтительнее, потому что это дорого, но по мере необходимости вы можете использовать несколько сеансов factory с разными флешмодами для разных требований.

Ответ 3

У меня тоже была эта проблема! Я использую транзакцию аннотации Spring (@Transactional), и я получаю некоторый метод, фактически выполняющий session.flush() и другие не!

Из моего журнала отладки я:

transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!

Session.close() должен вызываться из Spring TransationManager, но я не уверен, что происходит: я дважды проверил конфигурацию Spring, и я не могу спорить, почему это происходит. Я продолжаю расследование, и я перескажу любой намек, но если у кого-то есть полезный совет, я был бы очень благодарен: o)

Обновление: проблема связана с режимом спящего режима спящего режима = MANUAL: он не сбрасывал объекты в конце транзакции Spring.

Вы можете проверить свой текущий режим очистки с помощью чего-то вроде:

SessionFactoryUtils.getSession(mySessionFactory(), false).getCurrentSession().getFlushMode()


ОБНОВЛЕНИЕ [РЕШЕНО ДЛЯ МЕНЯ]:

Я много вникнул в свою проблему и нашел причину проблемы и обходной путь.

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

Я обнаружил, что:

  • проблема заключалась в том, что flushMode установлен на FlushMode.MANUAL, когда я ввел транзакцию (которая не запускает операцию сброса при совершении транзакции);

  • Это, в свою очередь, было связано с чем-то неприятным между Spring и ZK (плохие транзакции были из ZK-композиторов - если вы не знаете ZK, их вызывают из сервлетов, что примерно эквивалентно Struts 'действия);

  • точная проблема заключается в том, что Spring OpenSessionInViewFilter неправильно взаимодействует с фильтрами ZK: сеанс Hibernate, предоставляемый OpenSessionInViewFilter, не корректно устанавливает режим очистки. Один композитор ZK хорошо работает (я тестировал его из некоторых тестов JUnit), а также только OpenSessionInViewFilter (я тестировал его с простого сервлета с помощью WebApplicationContextUtils).

Заключение: я вызываю session.flush() в конце каждого метода @Transactional в моих композиторах, и я перейду на Vaadin (гораздо проще для интеграции, кажется).

Ответ 4

Для вашей конкретной потребности (промывка при каждом вызове метода DAO) вы можете установить режим очистки сеанса на FlushMode.ALWAYS. Из документации спящего режима:

The Session is flushed before every query.

Ответ 5

установка свойства hibernate.transaction.flush_before_completion в true может помочь.

<prop key="hibernate.transaction.flush_before_completion">true</prop>

https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/
" Если включено, сеанс будет автоматически очищаться во время фазы до завершения завершения транзакции. Предпочтительным является встроенное и автоматическое управление контекстом сеанса, см. Раздел 2.5 "Контекстные сеансы".