hibernate不一致:session返回旧值

时间:2012-04-17 14:27:06

标签: hibernate jsf caching page-refresh

我正在使用一个JSF项目的Hibernate。

在主页面中,我有一个表示对象列表的数据表。

我使用Hibernate成功更新了对象的属性(在数据表中找到)。更新后,通过使用“xxx?faces-redirect = true”重定向来刷新页面。我重定向页面,以避免“重复表单提交”类问题。

然后,如果我多次点击F5,更新对象的旧属性值可能会返回到页面。

据我所知,这是一个Hibernate会话问题。因为如果我在使用它们后立即关闭每个会话,则不会发生此问题。但是,由于延迟抓取策略,我无法在事务后关闭会话。

简而言之,虽然hibernate已成功更新,但它可能会带来旧对象的价值。我怎样才能避免这样的问题?

ps:我怀疑Hibernate的缓存机制,我使用以下方法禁用了第一级和第二级缓存:

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

但它也不起作用。

更新:在@Johanna的回复之后,我控制了会话实例的id,并注意到我的HibernateUtil类在大多数时间内返回一个不同的会话或者打开一个新的会话。这是getSession()方法:

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

我认为,一旦我开了一个会话,我会用该会话进行所有这样的列表,更新等。因为我在getSession()方法中进行了必要的控制。我在哪里犯了错误?

1 个答案:

答案 0 :(得分:4)

use_query_cache和use_second_level_cache都不能禁用第一级缓存。第一级缓存始终打开。

如果您确实不想使用第一级缓存,则必须使用StatelessSession而不是Session。但StatelessSession功能较少,您需要的一些方法可能会丢失。

如果您只想从第一级缓存中删除一些对象,可以使用Session.evict()。

尽管如此,我想知道为什么Hibernate会向您展示旧的价值。如果每个数据库实体在会话中只有一个实例(即,您更新的对象的实例与列表中显示的实例相同),则不应发生这种情况。如果你使用两个不同的实例,那么它是正常的Hibernate呈现旧值(如果你使用两个Session实例,一个用于列表,一个用于更新,那么你也可以在列表中获得旧值)。因此,在修复应用程序时,可能不必逐出该对象。

更新后编辑: 在您的短代码中,如果您作为单个用户使用该应用程序,我无法理解为什么会出现错误。

但一般情况下:您使用JSF,因此它可能是一个可供许多用户使用的Web项目。

Hibernate Session对象不是线程保存的,i。即如果不同的用户同时使用它,它可能无法工作。每个用户都需要自己的会话对象。因此,你可以将Hibernate会话实例存储在Http会话实例中(有时你甚至必须使用'synchronized'方法(或对象),因为用户在第一个请求的答案到达之前第二次按下按钮)。

第二次编辑:我认为你遇到与this question相同的问题。

可能您从任何地方复制了代码,例如引用问题的DAO。我想你的HibernateUtil类,你从任何地方复制的代码,都将hibernate会话存储在ThreadLocal对象中,i。即一个hibernate会话绑定到一个线程。

但是你正在做一个网络项目。你应该将一个Hibernate会话绑定到一个用户(或浏览器),i。即到一个Http会话。但是您不知道在哪个线程中处理来自一个http会话的请求。因此,在您的解决方案中,相同的Http会话可能会获得不同的Hibernate会话,或者可能不同的Http会话可能会获得相同的Hibernate会话。这取决于您的Http服务器。

解决方案:将Hibernate会话放入Http会话(并且使用ThreadLocal对象)。您可以使用HttpServletRequest.getSession()HttpSession.getAttribute() / HttpSession.setAttribute()获取Http会话对象,您可以设置Hibernate会话和其他与Http会话相关的数据。