JPA 并发问题“在发布批次时它仍然包含 JDBC 语句”

新手上路,请多包涵

我有一个并发问题,我试图用一个 while 循环来解决,该循环尝试多次保存一个实体,直到它达到某个最大重试次数。我想避免谈论是否有其他方法可以解决这个问题。我还有其他关于此的 Stackoverflow 帖子。 :) 长话短说:在派生的列上有一个唯一约束,并且包括一个不断递增以避免冲突的数字部分。在一个循环中,我:

  1. 选择最大值(some_value)
  2. 增加结果
  3. 尝试用这个新结果保存新对象
  4. 显式刷新实体,如果由于唯一索引而失败,我会捕获 DataAccessException。

所有这些似乎都有效,除非循环返回到步骤 1 并尝试选择,我得到:

 17:20:46,111 INFO  [org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl] (http-localhost/127.0.0.1:8080-3) HHH000010: On release of batch it still contained JDBC statements
17:20:46,111 INFO  [my.Class] (http-localhost/127.0.0.1:8080-3) MESSAGE="Failed to save to database. Will retry (retry count now at: 9) Exception: could not execute statement; SQL [n/a]; constraint [SCHEMA_NAME.UNIQUE_CONSTRAINT_NAME]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement"

并捕获了一个新的异常。似乎导致违反唯一约束并抛出 DataAccessException 的第一次刷新不会清除实体管理器的批次。处理这个问题的合适方法是什么?我将 Spring 与 JPA 一起使用,并且无法直接访问实体管理器。我想我可以在需要时注入它,但这是解决这个问题的痛苦方法。

原文由 Chris Williams 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

你不能那样做 - 一旦你刷新某些东西并且它失败并抛出异常,事务将被标记为回滚。这意味着您捕获异常并继续执行并不重要,您最终会回滚。实际上,抛出什么异常并不重要——默认情况下,Spring 的事务管理器将在每个 未检查 的异常上回滚。您可以通过在 @Transactional 注释上专门定义 noRollbackFor 来克服它(假设您使用的是注释驱动程序事务)

编辑 - 如果违反约束,它也不会帮助您,因为事务可能会在数据库级别标记为回滚。

原文由 paranoidAndroid 发布,翻译遵循 CC BY-SA 3.0 许可协议

我发现这个问题得到了同样的错误。在我的例子中,问题是由触发器和行锁的奇怪组合引起的(请参阅 PSQLException and lock issue when trigger added on table )。然而,花了一些时间才发现这个错误只是主要错误的结果,而不是原因。当 Hibernate 刷新会话并发生某些约束冲突时,它会收到一些 JDBC 异常,并在 finally 块中尝试调用 abortBatch 。当任何语句保留在会话中时,Hibernate 会发出此警告,尽管实际错误应该在之前的某个地方进行搜索。

原文由 Tomáš Záluský 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题