如何中断休眠会话?

2022-09-04 22:39:01

在Hibernate引用中,多次指出

Hibernate 引发的所有异常都是致命的。这意味着您必须回滚数据库事务并关闭当前 .不允许你继续使用引发异常的 。SessionSession

我们的一个旧版应用程序使用单个会话将文件中的许多记录更新/插入到数据库表中。每个记录更新/插入都在单独的事务中完成,然后提交该事务(或在发生错误时回滚)。然后,对于下一条记录,将打开一个新事务,依此类推。但是,在整个过程中使用相同的会话,即使 a 在处理过程中被捕获。我们在 JBoss 4.2 上使用 Oracle 9i btw 和 Hibernate 3.24.sp1。HibernateException

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

但是,我们发现在测试整个应用程序时无法重现会话失败(顺便说一句,这是压力测试还是...?)。我们考虑关闭数据库的侦听器,但我们意识到该应用程序使一堆连接对数据库保持开放,并且侦听器不会影响这些连接。(这是一个Web应用程序,每晚由调度程序激活一次,但也可以通过浏览器激活。然后,我们试图在应用程序处理更新时终止数据库中的一些连接 - 这导致一些失败的更新,但随后应用程序高兴地继续更新其余记录。显然,Hibernate足够聪明,可以在引擎盖下重新打开断开的连接,而不会破坏整个会话。

因此,这可能不是一个关键问题,因为我们的应用程序即使在其原始形式下似乎也足够强大。但是,这个问题一直困扰着我。我想知道:

  1. 在什么情况下,在抛出 后,休眠会话真的变得不可用(更新:以及症状是什么)?HibernateException
  2. 如何在测试中重现这一点(更新:最好是在集成中,而不是单元测试中)?
  3. (这种测试的正确术语是什么?

答案 1

在什么情况下,在抛出休眠异常后,休眠会话真的变得不可用?

有趣的问题。我很确定我已经看到过这样的情况,在这种异常之后,会话仍然“工作”。问题是,也许这并不能保证。我需要再深入一点。

更新:引用Hibernate论坛中Hibernate开发人员的以下消息

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

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

如何在测试中重现这一点?

您可以故意违反导致抛出子类的条件,例如,通过违反完整性约束来获得约束暴力异常。那么这样的事情呢:

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?

但我不确定这能证明什么。我的意思是,如果会议仍在进行,我们只能就这一特定情况得出结论。

更新:忘记我的建议,它不会证明什么。实际上,我认为在.因此,与其试图证明什么,我想正确的做法是遵循建议(或建议的替代方案,但我只是请求一个新的,并且它适用于每个事务,无论是否抛出异常)。HibernateExceptionSessionclose

这种测试的正确术语是什么?

集成测试?鲁棒性测试?


答案 2

有趣的一个。最好的方法是去看看Hibernate的来源。据我所知,除了以下东西之外,它没有太多的状态:Session

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

因此,就我所玩过的,实际上在错误的事务中幸存下来,除了一级缓存可能略有不准确;要解决此问题,您可能更愿意调用或显式重新同步状态。Sessionsession.refreshsession.load

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