尝试重试事务性方法因违反约束而失败

Attempting to retry transactional method fails with constraint violation

我正在尝试创建唯一的随机标记并将它们保存到数据库中。因为有多个服务器同时做这个,所以采取的方法是尝试保存一个随机生成的token,但是创建一个新的token,如果不行再试。

我们发现重试功能不起作用。看起来是事务没有回滚的情况。事务是注释驱动的,我们使用 Hibernate 作为 JPA 提供程序。

我们的代码看起来像这样:

@Autowired EntityManager em;

Token save(Token t, int attempts) {
  if(attempts > SOME_MAX) {
    throw new RuntimeException("Could not generate Token");
  }

  t.setId(MyRandomNumberGenerator.next());
  try {
    saveToDb(t);
  catch(PersistenceException e) {
      t = save(t.clone(), ++attempts);
  }
  return t;
}

@Transactional(propogation=Propagation.REQUIRES_NEW)
boolean saveToDb(Token t) {
    em.persist(t);
    em.flush();
}

调用 save 时已经有一个事务在进行,我已经在 saveToDb 的 catch 块中尝试了各种方法来尝试确保从当前上下文中删除原始的违规令牌,但是没有无论我尝试什么,每次调用 saveToDb 都会抛出一个违反约束的异常。

本意是当 saveToDb 失败时,回滚由它创建的新事务,以便 save 方法可以重试。

有没有办法使这种方法奏效,或者我应该放弃它并尝试其他方法?

我相信异常之后您需要新的 EM,因为异常之后 EM 的状态是未知的。

我相信如果直接从同一个 class 调用跨国方法,有可能甚至不考虑注释!

来自Spring page

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional.

看看here.