Спящий режим сеанса 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 "Контекстные сеансы".