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

2022-09-03 14:24:02

我有一个并发问题,我试图用一个 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"

并捕获新的异常。这似乎是导致唯一约束冲突的第一次刷新,并引发不清除实体管理器的批处理。处理这个问题的适当方法是什么?我正在将Spring与JPA一起使用,并且无法直接访问实体管理器。我想如果我需要它,我可以注射它,但这是解决这个问题的痛苦。DataAccessException


答案 1

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

编辑 - 如果发生此约束冲突,它也不会对您有所帮助,因为事务可能会在数据库级别标记为回滚。


答案 2

我发现这个问题得到了同样的错误。在我的情况下,问题是由触发器和行锁的奇怪组合引起的(请参阅在表上添加触发器时的 PSQLException 和锁问题)。但是,花了一些时间才发现此错误只是主要错误的结果,而不是原因。当休眠刷新会话并发生一些约束冲突时,它会收到一些JDBC异常,并在最后的块中尝试调用 。当任何语句保留在会话中时,Hibernate 会发出此警告,但实际错误应搜索之前的某个位置。abortBatch


推荐