在最近的任务中,在创建对象后,我将结果刷新到数据库。数据库表有一个唯一约束,这意味着如果我尝试第二次刷新同一条记录,我将得到 ConstraintViolationException
。示例片段如下所示:
createEntityAndFlush(result);
sendAsyncRequestToThirdSystem(param);
createEntityAndFlush 的代码:
private T createEntityAndFlush(final T entity) throws ServiceException {
log.debug("Persisting {}", entity.getClass().getSimpleName());
getEntityManager().persist(entity);
getEntityManager().flush();
return entity;
}
我使用flush的原因是我想确保ConstraintViolationException
将在完成交易之前抛出,从而调用 sendAsyncRequestToThirdSystem
。但事实并非如此,因为 sendAsyncRequestToThirdSystem
抛出异常后被调用。
为了在竞争条件下测试代码,我使用了 ManagedExecutorService 并创建了两个可运行的任务 (Future<?> submit(Runnable task))
复制传入的请求。
最终,通过尝试为每个唯一的请求 id 在新表上执行锁定来解决问题,但我想知道我的第一种方法哪里错了(例如,错误使用闪存,ManagedExecutorService 负责尴尬的情况)行为)。提前致谢!
最佳答案
问题是,虽然 flush()
确实将更改刷新到数据库中,但事务仍然处于打开状态,并且在事务提交 (这可能取决于数据库,但至少对于 Postgres 和任何使用数据库的 MVCC 而言)。
因此,您需要确保 createEntityAndFlush(result);
在自己的事务中运行,可能使用 @Transactional(propagation = Propagation.REQUIRES_NEW)
(或相当于,如果不使用 Spring)来查看是否违反了唯一索引。
关于java - JPA使用flush来触发异常并停止执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59900014/