Поведение сброса Hibernate Session [и Spring @Transactional] - PullRequest
16 голосов
/ 20 мая 2010

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

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

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

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

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

После завершения метода @Transactional в DAO очистка может НЕ произойти? Кажется, это не правило [Я уже вижу это].

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

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

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

p.s. Я где-то читал, что @Transactional связан с транзакцией БД. Метод возвращается, транзакция должна быть зафиксирована. Я не вижу, чтобы это случилось.

Ответы [ 6 ]

5 голосов
/ 20 мая 2010

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

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

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

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

Сообщите, если найдете что-нибудь интересное.

3 голосов
/ 09 августа 2013

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

@Autowired
private SessionFactory sessionFactory;

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

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

2 голосов
/ 01 марта 2011

У меня тоже была эта проблема! Я использую транзакцию аннотации 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)

Обновление: похоже, проблема связана с режимом очистки сеанса спящего режима = РУЧНОЙ: он не сбрасывал объекты в конце транзакции Spring.

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

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


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

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

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

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

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

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

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

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

0 голосов
/ 23 февраля 2018

Я бы не рекомендовал использовать hibernate.transaction.flush_before_completion глобально для повышения производительности.

Кроме того, вы можете самостоятельно управлять транзакциями:

@PersistenceContext
private EntityManager em;
....
public void save(){
    try
    {         
        em.getTransaction().begin();                

        <update database>

        em.getTransaction().commit();                        
    }
    catch(Throwable th) {
        em.getTransaction().rollback();
        //log, rethrow
    }        
}
0 голосов
/ 02 февраля 2015

Установка свойства "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« Контекстные сеансы »».

0 голосов
/ 02 марта 2011

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

The Session is flushed before every query.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...