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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39734796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 21:25:08  来源:igfitidea点击:

JPA concurrency issue "On release of batch it still contained JDBC statements"

javaspringhibernatejpaconcurrency

提问by Chris Williams

I have a a concurrency issue I tried to solve with a while loop that attempts to save an entity multiple times until it hits some max retry count. I'd like to avoid talking about whether or not there are other ways to solve this problem. I have other Stackoverflow posts about that. :) Long story short: there's a unique constraint on a column that is derived and includes a numeric portion that keeps incrementing to avoid collisions. In a loop, I:

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

  1. select max(some_value)
  2. increment the result
  3. attempt to save new object with this new result
  4. explicitly flush the entity and, if that fails because of the unique index, I catch a DataAccessException.
  1. 选择最大值(some_value)
  2. 增加结果
  3. 尝试使用此新结果保存新对象
  4. 显式刷新实体,如果由于唯一索引而失败,我会捕获 DataAccessException。

All of this seems to work except when the loop goes back to step 1 and tries to select, I get:

所有这些似乎都有效,除非循环返回到步骤 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"

And a new Exception is caught. It seems like the first flush that causes the unique constraint violation and throws the DataAccessExceptiondoesn't clear the entity manager's batch. What's the appropriate way to deal with this? I'm using Spring with JPA and don't have direct access to the entity manager. I guess I could inject it if I need it but that's a painful solution to this problem.

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

采纳答案by paranoidAndroid

You cannot do that - once you flush something and it fails and an exception is thrown, the transaction will be marked as roll back. That means it doesnt matter that you catch the exception and proceed, you'll end up with a rollback. Actually it doesnt matter at all what exception was thrown - by default Spring's transaction manager will rollback on every uncheckedexception. You can overcome it by specifically defining a noRollbackForon the @Transactionalannotation (providing you are using annotation driver transactions)

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

Edit - it also won't help you in case of this constraint violation, since the transaction will be probably marked as rollback at the database level.

编辑 - 如果违反此约束,它也无济于事,因为事务可能会在数据库级别被标记为回滚。

回答by Tomá? Zálusky

I found this question getting same error. In my case the problem was caused by weird combination of trigger and row lock (see PSQLException and lock issue when trigger added on table). However it took some time to discover this error is just consequence of primary error, not the cause. When Hibernate flushes session and some constraint violation happens, it receives some JDBC exception and in the finally block it tries to call abortBatch. When any statement remains in session, Hibernate emits this warning, though the actual error should be search for somewhere before.

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