首页 文章

hibernate不一致:session返回旧值

提问于
浏览
3

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

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

我使用Hibernate成功更新了对象的属性(在数据表中找到) . 更新后,通过使用"xxx?faces-redirect=true"重定向来刷新页面 . 我重定向页面以避免"duplicate form submission"类问题 .

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

据我所知,这是一个Hibernate会话问题 . 因为如果我在使用它们后立即关闭每个会话,这个问题不会在事务发生后关闭会话 .

简而言之,尽管已成功更新,但hibernate可能会带来旧对象的 Value . 我怎么能避免这样的问题?

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 回答

  • 4

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

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

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

    不过我想知道为什么Hibernate会给你带来旧的 Value . 如果每个数据库实体在会话中只有一个实例(即,您更新的对象的实例与列表中显示的实例相同),则不应该发生这种情况 . 如果你使用两个不同的实例,那么它是正常的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() 获取Http会话对象,使用 HttpSession.getAttribute() / HttpSession.setAttribute() 可以设置Hibernate会话和其他与Http会话相关的数据 .

相关问题