Hibernate 休眠不一致:会话返回旧值

Hibernate 休眠不一致:会话返回旧值,hibernate,jsf,caching,page-refresh,Hibernate,Jsf,Caching,Page Refresh,我正在JSF项目后面使用Hibernate 在主页面中,我有一个datatable,表示对象列表 我使用Hibernate成功地更新了对象(在datatable中找到)的属性。更新后,通过使用“xxx?faces redirect=true”重定向来刷新页面。我重定向页面以避免“重复表单提交”之类的问题 然后,如果我多次按F5,更新对象的旧属性值可能会返回页面 据我所知,这是一个Hibernate会话问题。因为如果我在每次会话使用后立即关闭它们,这个问题就不会发生。但是,由于延迟抓取策略,我无法

我正在JSF项目后面使用Hibernate

在主页面中,我有一个datatable,表示对象列表

我使用Hibernate成功地更新了对象(在datatable中找到)的属性。更新后,通过使用“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>

我假设,一旦我有了一个会话,我就可以在该会话中列出、更新等所有内容。因为我在getSession()方法中创建了必要的控件。哪里出错?

无论是使用查询缓存还是使用二级缓存都不能禁用一级缓存。第一级缓存始终处于启用状态

如果确实不想使用第一级缓存,则必须使用无状态会话而不是会话。但是无状态会话的功能较少,并且可能缺少您需要的一些方法

如果只想从一级缓存中删除几个对象,可以使用Session.execute()

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

更新后编辑: 在您的简短代码中,我不明白如果您作为单个用户使用该应用程序,为什么会出现错误

但一般来说:您使用JSF,因此它可能是一个可以被许多用户使用的web项目

Hibernate会话对象不是线程保存,即。E如果不同的用户同时使用它,它可能不会起作用。每个用户都需要自己的会话对象。因此,您可以将Hibernate会话实例存储在Http会话实例中(即使这样,有时您也必须使用“同步”方法(或对象),以防用户在第一个请求的答案到达之前第二次按下按钮)

第二次编辑:我认为你的问题和我的一样

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

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


解决方案:将Hibernate会话放入Http会话(不要使用ThreadLocal对象)。使用
HttpServletRequest.getSession()
HttpSession.getAttribute()
/
HttpSession.setAttribute()
可以设置Hibernate会话和其他与Http会话相关的数据。我创建了一个控件,以避免有两个不同的会话。因此,如果有一个打开的会话,我不创建另一个会话,而是返回打开的会话。因此,不应存在两个不同的会议。在列出、更新等时使用现有会话是否有问题。它应该只与一个会话一起工作。我建议您在调试模式下启动应用程序,并检查您更新的实例和获得旧值的实例是否为同一实例(Eclipse调试器中的地址或实例ID相等)。我如您所说检查了ID,我需要用我的观察结果更新问题。等待您的帮助,谢谢..在阅读了您的回复后,我可以说我现在是作为单个用户进行测试的。作为单个用户,为什么要从getSession()方法获得不同的会话?该方法有问题吗?此对象中也存在问题。
HibernateUtil.session
。确保始终是同一个实例。调试(getSession()中至少有一个断点)可以帮助您。
public static Session getSession(){
    Session se = HibernateUtil.session.get();
    if(se == null)
    {
        se = sessionFactory.openSession();
        HibernateUtil.session.set(se);
    }
    return se;
}