2012-04-17 3 views
3

Я использую Hibernate за проектом JSF.

На главной странице у меня есть datatable, представляющий список объектов.

Я успешно сделаю обновление свойства объекта (найденного в datatable) с помощью Hibernate. После обновления страница обновляется путем перенаправления с использованием «xxx? Faces-redirect = true». Я перенаправляю страницу, чтобы избежать проблем с дублированием формы.

Затем, если я нажму F5 несколько раз, значение старой версии обновленного объекта может вернуться на страницу.

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

В общем, hibernate может принести старое значение объекта, хотя оно было успешно обновлено. Как я могу избежать такой проблемы?hibernate inconsistency: session возвращает старое значение

пс: Я подозревал о кэшировании механизмов Hibernate, и я отключил кэш первого и второго уровня с помощью:

<property name="hibernate.cache.use_query_cache">false</property> 
<property name="hibernate.use_second_level_cache">false</property> 

, но он не работает слишком ..

Update: После того, как ответ @Johanna, я контролировал идентификаторы экземпляров сеанса и заметил, что мой класс HibernateUtil возвращает другой сеанс большую часть времени или открывает новый сеанс. Вот метод getSession():

public static Session getSession(){ 
    Session se = HibernateUtil.session.get(); 
    if(se == null) 
    { 
     se = sessionFactory.openSession(); 
     HibernateUtil.session.set(se); 
    } 
    return se; 
} 

я предположить, что когда-то у меня сеанс, я сделать все такое перечисление, обновление и т.д. с этой сессией. Потому что я делаю необходимые элементы управления в методе getSession(). Где я совершу ошибку?

ответ

4

Ни use_query_cache, ни use_second_level_cache не могут отключить кеш первого уровня. Кэш первого уровня всегда включен.

Если вы действительно не хотите использовать кеш первого уровня, вам необходимо использовать StatelessSession вместо сеанса. Но StatelessSession имеет меньше функциональности, и некоторые из методов, которые вам нужны, могут отсутствовать.

Если вы хотите удалить только несколько объектов из кеша первого уровня, вы можете использовать Session.evict().

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

EDIT после вашего обновления: В вашем коротком кодексе я не вижу, почему вы получаете ошибки, если вы используете одного пользователя в качестве одного пользователя.

Но в целом: вы используете JSF, поэтому это, вероятно, веб-проект, который может использоваться многими пользователями.

Сессионный объект Hibernate не является ниспадающим, i. е. он, вероятно, не будет работать, если разные пользователи будут использовать его одновременно. Каждому пользователю нужен собственный объект сеанса.Таким образом, вы можете хранить экземпляр сеанса Hibernate в экземпляре сеанса Http (и даже тогда иногда вы должны использовать «синхронизированные» методы (или объекты) только для случая, когда пользователь нажимает второй раз на кнопку, прежде чем ответ от первого запроса будет получен).

2nd EDIT: Я думаю, у вас есть та же проблема, что и у this question.

Возможно, вы скопировали свой код из любого места, как DAO указанного вопроса. Я предполагаю, что ваш класс HibernateUtil, код которого вы скопировали из любого места, хранит сеанс hibernate в объекте ThreadLocal, т.е. е. один сеанс гибернации связан с одним потоком.

Но вы делаете веб-проект. Там вы должны связать одну сессию Hibernate с одним пользователем (или браузером), т.е. е. к одной сессии Http. Но вы не знаете, в какой поток обрабатывается запрос с одного сеанса http. Таким образом, в вашем решении один и тот же сеанс Http может иметь разные сеансы Hibernate или, возможно, разные Http-сессии могут получать один и тот же сеанс Hibernate. Это зависит от вашего Http-сервера.

Решение: Поместите сеанс Hibernate в сеанс Http (и do не использует объект ThreadLocal). Вы получаете объект сеанса Http с HttpServletRequest.getSession() и с HttpSession.getAttribute()/HttpSession.setAttribute() вы можете установить сеанс Hibernate и другие связанные с Http-данными данные.

+0

Я делаю контроль, чтобы избежать двух разных сеансов. Поэтому, если есть открытый сеанс, я не создаю другого, я возвращаю открытый сеанс. Следовательно, не должно существовать двух разных сеансов. Является ли проблема использовать существующий сеанс во время листинга, обновления и т. Д. –

+0

Он должен работать только с одним сеансом. Я рекомендую вам запустить приложение в режиме отладки и проверить, является ли экземпляр, который вы обновляете, и экземпляр, где вы получаете старое значение, - это один и тот же экземпляр (адреса или идентификаторы экземпляров в отладчике Eclipse равны) – Johanna

+0

I chekced ids, как вы сказали, и мне нужно было обновить вопрос своими наблюдениями. В ожидании вашей помощи, спасибо .. –

Смежные вопросы