我正在尝试创建唯一的随机令牌并将其保存到数据库中。因为有多个服务器同时执行此操作,所以已采取的方法是尝试保存随机生成的令牌,但创建新令牌并在不起作用时再试一次。
我们发现重试功能不起作用。似乎是交易没有回滚的情况。事务是注释驱动的,我们使用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方法可以再次尝试。
有没有办法让这种方法有效,还是应该废弃它并尝试其他方法?
答案 0 :(得分:1)
我相信如果你直接从同一个班级调用跨国方法,有可能甚至不考虑注释!
在代理模式(默认设置)下,只拦截通过代理进入的外部方法调用。这意味着实际上,自调用目标对象中的一个方法调用目标对象的另一个方法,即使被调用的方法用@Transactional标记,也不会在运行时导致实际的事务。
看看here。
答案 1 :(得分:-1)
我相信在异常之后你需要新的EM,因为异常后EM的状态是未知的。