代码之家  ›  专栏  ›  技术社区  ›  Péter Török

如何中断休眠会话?

  •  13
  • Péter Török  · 技术社区  · 15 年前

    在Hibernate引用中,多次声明

    休眠引发的所有异常都是致命的。这意味着你必须后退 数据库事务并关闭当前 Session .不允许您继续 与A一起工作 会话 这引发了一个例外。

    我们的一个遗留应用程序使用一个会话来更新/插入文件中的许多记录到一个DB表中。每个记录更新/插入都在一个单独的事务中完成,然后提交该事务(或者在发生错误时回滚)。然后为下一个记录打开一个新事务,依此类推。但在整个过程中使用相同的会话,即使 HibernateException 在处理过程中被捕获。我们在JBoss4.2上使用Oracle9iBTW和Hibernate3.24.sp1。

    读了这本书,我意识到这个设计可能会失败。因此,我重构了应用程序,以便对每个记录更新使用单独的会话。在一个模拟会话工厂的单元测试中,我可以验证它现在正在为每个记录更新请求一个新的会话。到目前为止,一切都很好。

    但是,我们发现在测试整个应用程序时无法重现会话失败(这是压力测试btw,还是…?)。我们考虑关闭数据库的侦听器,但我们意识到应用程序正在保持一系列与数据库的连接打开,并且侦听器不会影响这些连接。(这是一个网络应用程序,每天晚上由调度程序激活一次,但也可以通过浏览器激活。)然后我们试图在应用程序处理更新时终止数据库中的某些连接-这导致了一些失败的更新,但随后应用程序高兴地继续更新其余记录。显然,Hibernate非常聪明,可以在不中断整个会话的情况下重新打开引擎盖下断开的连接。

    所以这可能不是一个关键的问题,因为我们的应用程序看起来足够强大,即使是在它的原始形式。然而,这个问题一直困扰着我。我想知道:

    1. 在什么情况下,休眠会话在 抛出异常 投掷( 更新: 有什么症状?
    2. 如何在测试中重现( 更新: 最好是在集成中,而不是在单元测试中?
    3. (这种测试的恰当术语是什么?)
    4 回复  |  直到 15 年前
        1
  •  4
  •   Péter Török    15 年前

    在什么情况下,引发HibernateException后,Hibernate会话确实变得不可用?

    有趣的问题。我很肯定我已经看到过这样的情况,在这种例外之后,会话仍然“工作”。问题可能是这并不能保证。我需要再多挖一点。

    更新: 报价 this message 来自Hibernate论坛中的Hibernate开发人员:

    当发生任何异常时,应丢弃休眠会话。相对于数据库,它可以处于不一致的状态。只读会话不是这样,因为它不使用任何会话级缓存。或者,您可以在发生异常时清除会话级缓存(但我个人不喜欢这种方法,因为它不是一个干净的解决方案,而且可能导致将来的问题和问题)。

    所以问题不在于 Session 是否“技术上可用”,问题在于它的行为可能与预期不符。你显然不想这样。

    如何在测试中重现?

    您可以故意违反导致抛出子类的条件,例如违反完整性约束以获取 ConstraintViolationException . 像这样的情况怎么样:

    Session session = HibernateUtil.getCurrentSession();
    
    try {
        session.beginTransaction();    
        // execute some code that violates a unique constraint
        ...
        session.getTransaction().commit();  
    } catch (HibernateException e) {
        session.getTransaction().rollback();
    }
    
    // keep using the session
    try {
        session.beginTransaction();    
        ...
        session.getTransaction().commit();  
    } catch (HibernateException e) {
        session.getTransaction().rollback();
    }
    // do we reach this point?
    

    但我不确定这会证明什么。我的意思是,如果会议仍在进行中,我们只能对这个特定的案件作出结论。

    更新: 忘了我的建议,它不会证明什么。事实上,我认为在一个 HibernateException . 所以,我不想证明什么,我想正确的做法是遵循建议(或建议的替代方案),但我只要求一个新的 会议 close 它适用于每个事务,是否引发异常)。

    这种测试的恰当术语是什么?

    集成测试?稳健性测试?

        2
  •  3
  •   BorisOkunskiy    15 年前

    有趣的一个。最好的方法是去看看Hibernate的来源。据我所知, Session 除了以下内容外,不会携带太多状态:

    最后一点,事务本身的回滚不会以任何方式干扰会话状态,请参见 JDBCTransaction .

    就我而言, 会话 实际上,除了一级缓存可能有点不准确之外,还可以在错误的事务中存活下来;要解决这个问题,您可能更愿意调用 session.refresh session.load 明确地重新同步状态。

    编辑:测试JDBC异常的最快方法可能是 session.createSQLQuery("something offensive to SQL parser").executeUpdate() --你会得到一个完美的 SQLGrammarException --和一个中断的事务=)

        3
  •  1
  •   Alexander Torstling    15 年前

    我的观点是

    1. 几乎不可能知道Hibernate是否可以工作,它遇到了一个意外的情况,现在正以未定义的状态运行-基本上,您将通过在会话上执行更多的操作来调用UB。

    2. 想法-注册一个拦截器并在其中抛出一个HibernateException-希望Hibernate不会捕获它:d

    3. 故障注入?

        4
  •  0
  •   james    15 年前

    为测试创建会话的子类。实现它以在某些特定场景中引发异常。使用特定于测试的Hibernate配置,该配置将Hibernate设置为使用测试会话。