我有一个并发问题,我试图用一个 while 循环来解决,该循环尝试多次保存一个实体,直到它达到某个最大重试次数。我想避免谈论是否有其他方法可以解决这个问题。我还有其他关于此的 Stackoverflow 帖子。 :) 长话短说:在派生的列上有一个唯一约束,并且包括一个不断递增以避免冲突的数字部分。在一个循环中,我:
- 选择最大值(some_value)
- 增加结果
- 尝试用这个新结果保存新对象
- 显式刷新实体,如果由于唯一索引而失败,我会捕获 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 许可协议
你不能那样做 - 一旦你刷新某些东西并且它失败并抛出异常,事务将被标记为回滚。这意味着您捕获异常并继续执行并不重要,您最终会回滚。实际上,抛出什么异常并不重要——默认情况下,Spring 的事务管理器将在每个 未检查 的异常上回滚。您可以通过在
@Transactional
注释上专门定义noRollbackFor
来克服它(假设您使用的是注释驱动程序事务)编辑 - 如果违反约束,它也不会帮助您,因为事务可能会在数据库级别标记为回滚。