尝试重试事务方法会因约束违规而失败

时间:2015-02-25 00:28:18

标签: java spring hibernate jpa transactions

我正在尝试创建唯一的随机令牌并将其保存到数据库中。因为有多个服务器同时执行此操作,所以已采取的方法是尝试保存随机生成的令牌,但创建新令牌并在不起作用时再试一次。

我们发现重试功能不起作用。似乎是交易没有回滚的情况。事务是注释驱动的,我们使用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方法可以再次尝试。

有没有办法让这种方法有效,还是应该废弃它并尝试其他方法?

2 个答案:

答案 0 :(得分:1)

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

来自Spring page

  

在代理模式(默认设置)下,只拦截通过代理进入的外部方法调用。这意味着实际上,自调用目标对象中的一个方法调用目标对象的另一个方法,即使被调用的方法用@Transactional标记,也不会在运行时导致实际的事务。

看看here

答案 1 :(得分:-1)

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