首页 文章

抛出异常后使用Current Sesssion

提问于
浏览
1

根据Hibernate documentation,在Hibernate抛出异常后使用Session是不安全的 .

如果Session抛出异常(包括任何SQLException),则立即回滚数据库事务,调用Session.close()并丢弃Session实例 . Session的某些方法不会使会话保持一致状态 . Hibernate抛出的异常都不能被视为可恢复的 . 确保通过在finally块中调用close()来关闭Session .

在我的代码中,我正在进行批量插入 . 我正在使用 sessionFactory.getCurrentSession() 方法来获取会话 . 我的代码是这样的 .

try {
  //some code here....
  ....
  Table1Entity table1Entity = .......
  List<Table2Entity> table2Entities = .......
  Session currentSession = sessionFactory.getCurrentSession();
  for (int i = 0; i < table2Entities; i++) {
      .............
      currentSession.save(table2Entities.get(i));
      if(i % batchSize == 0 || i + 1 == table2Entities) {
        currentSession.flush();
        currentSession.clear();
    }
  }
} catch (Exception e) {
    currentSession.getTransaction().rollback();
    //currentSession.close(); //According to documentation Session should be closed here
    table1Entity.setError(true);
    currentSession.save(table1Entity);//According to documentation Session should not be used here
    .......
}

正如文档所说,在抛出异常之后不应该使用会话 . 我的问题是因为我正在使用 currentSession ,如何在catch块中保存 table1Entity ?我应该使用 openSession() 方法还是以任何其他方式打开新会话?


Edit: 更清楚的是,我要问的是,在现有的 currentSession 关闭后是否可以检索新的 currentSession .

2 回答

  • 0

    这是一个try..catch块 . 你怎么能确定在table1Entity上进行的任何处理都不会抛出Hibernate异常?如果在处理table1Entity时出现异常,那么尝试将其保存在当前会话中可能会产生更大的问题 .

    我的建议是你将表上的处理分成单独的try..catch块,并在每个块中单独调用save . 抛出异常后,尝试在catch块中的同一会话中保存事务是不安全的,并且假设table1Entity中没有问题,有时可能是违反直觉的 .

  • 0

    如果在与该数据库的连接中发生异常,我建议不要写入数据库 . 所以基本上,我认为你的方法有严重的问题,修复它很可能对你没有任何好处 .

    在这种情况下,您应该非常小心,无论如何,您的批次都不会抛出异常 . 因此,如果发生异常,您可以假设数据库无法访问,或者无论如何都不会接受任何尝试 . 将错误写入其他地方(已证明日志文件对此有用) .

    我可以看到你的方法似乎是可行的情况(比如我更新所有有效的方法,我标记的其他方法 . 识别“其他”我使用例外)但它旁边从来都不是一个好的想法,而是“诙谐”的情况 . - 不要诙谐,它不会得到回报 .

    而是以一种不会成为首选的方式编写批处理,而是返回一个说“我没有工作”并正确处理的正确结果 .

    所以在你的情况下:

    try {
      //some code here....
      ....
      Table1Entity table1Entity = .......
      List<Table2Entity> table2Entities = .......
      Session currentSession = sessionFactory.getCurrentSession();
      for (int i = 0; i < table2Entities; i++) {
          .............
    
          // HERE you need to make sure that this call would succeed
          currentSession.save(table2Entities.get(i));
          if(i % batchSize == 0 || i + 1 == table2Entities) {
            currentSession.flush();
            currentSession.clear();
        }
      }
      currentSession.save(table1Entity);
      currentSession.getTransaction().commit();
    } catch (Exception e) {
      currentSession.getTransaction().rollback();
      log.warn("Could not do what I wanted", e);
    }
    

    这要么全部完成,要么根本没有,并为您提供一个包含消息的正确堆栈跟踪,以及它所属的所有位置(日志) .

    也许你想在调用之前调查一个调用是否会成功 .

    如果你认为你必须做你想做的事,请在他的回答下阅读CodeNewbie的评论:创建table1Entry与 setGoingToWriteBatch(true) 然后在批 setBatchWritten(true) 的末尾 . 这样你就可以找到第一个为真的那个,但第二个不是 .

相关问题