当前位置: 首页 > 知识库问答 >
问题:

在引发异常后使用当前会话

卫阳炎
2023-03-14

根据Hibernate文档,在Hibernate抛出异常后使用会话是不安全的。

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

在我的代码中,我正在做批量插入。我正在使用会话工厂获取会话。我的代码是这样的。

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
    .......
}

正如留档所说,抛出异常后不应使用会话。我的问题是,由于我使用的是当前会话,我如何将table1Entity保存在catch块中?我应该使用open会话()方法或任何其他方式打开新会话吗?

共有2个答案

丰誉
2023-03-14

我建议不要写入数据库,以防数据库连接出现异常。所以基本上,我认为你的方法有严重的问题,修复它很可能对你没有任何好处。

在这种情况下,您应该非常小心,无论发生什么情况,您的批处理都不会抛出异常。因此,如果确实发生了异常,您可以假设数据库是不可访问的,或者无论如何不会接受任何尝试。将错误写到其他地方(日志文件已经被证明是有用的)。

我可以看到你的方法似乎是可行的(比如我更新了所有有效的方法,我标记的其他方法。为了识别“其他”,我使用了一个例外),但它实际上从来都不是一个好主意,而是一种“机智”的情况别那么机智,这不会有回报的。

取而代之的是,以一种方式写下你的批次,让那些不会成为首选的批次返回一个正确的结果,上面写着“我没有工作”,并适当地处理它。

所以在你的情况下:

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在他的答案下的评论:用< code > setGoingToWriteBatch(true)创建table1Entry,然后在批处理的末尾< code > setBatchWritten(true)。这样你就可以找到第一个是对的,而第二个不是。

舒飞捷
2023-03-14

这是一个try… catch块。你怎么能确定无论对table1Entity进行什么处理,都不会引发Hibernate异常?如果在处理table1Entity时确实出现了异常,那么试图将其保存在当前会话中可能会产生更大的问题。

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

 类似资料:
  • 我正在使用Spring In Action 3 Action学习Spring MVC,我已经实现了显示用户注册表的基本程序,一旦我们提交表单,它将使用进行验证。 这是我的Spring控制器: 这是我的Spitter类文件: 这是我的编辑。显示给用户注册的jsp文件: 要加载表单,我将访问URL为:,一旦表单被加载,我只需提交表单而无需输入任何详细信息,以便我可以检查我的表单是否得到验证。但是我得到

  • 本文向大家介绍在MySQL中使用“ TYPE = InnoDB”会引发异常吗?,包括了在MySQL中使用“ TYPE = InnoDB”会引发异常吗?的使用技巧和注意事项,需要的朋友参考一下 您可以使用ENGINE = InnoDB代替TYPE = InnoDB,因为TYPE的用法在MySQL 5.1版中已过时。 我们用于示例的版本是MySQL 8.0.12。让我们检查MySQL版本。查询如下-

  • 问题内容: 我有一个简单的方法,可将命令打印到屏幕上,扫描用户的输入,然后将其作为字符串返回。如果用户输入无效,它将通知用户并再次询问。该方法运行完美,但是我的讲师提到我们应该始终关闭资源,因此我回过头来添加了close方法,现在无论用户输入什么,每次调用该方法时都会收到NoSuchElementException。这是代码… 例外总是指向用户输入以scan.nextLine()。trim()开头

  • 在java手册中,建议在使用lock()和unlock()时使用try-finally,但是当try块中从未引发异常时,这也是必要的?例如:

  • 问题内容: 是否有可能在Java 引用上创建方法引用的原因 ?这样做可能永远是不正确的,但是会导致错误,以后很难找到: 问题答案: 是否有可能在Java 引用上创建方法引用的原因 ? 不是 ,但是Eclipse在这方面显然存在一个错误(编辑:此问题已得到修复)。根据规范,当您使用JDK的工具时,它会失败,并且在线上会出现NPE 。 证明:http://ideone.com/APWXna(或编译和本

  • 你可以使用raise语句 引发 异常。你还得指明错误/异常的名称和伴随异常 触发的 异常对象。你可以引发的错误或异常应该分别是一个Error或Exception类的直接或间接导出类。 如何引发异常 例13.2 如何引发异常 #!/usr/bin/python # Filename: raising.py classShortInputException(Exception):     '''A u