I'm trying to create unique random tokens and save them to a database. Because there are multiple servers doing this at the same time, the approach that has been taken is to attempt to save a randomly generated token, but create a new token and try again if it doesn't work.
We've discovered that the retry functionality is not working. It appears to be the case that the transaction has not rolled back. Transactions are annotation-driven, and we're using Hibernate as the JPA provider.
Our code looks something like this:
@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();
}
There is a transaction already going on when save gets called, and I've tried all sorts of stuff in the catch block of saveToDb to try and make sure the originating offending token is removed from the current context, but no matter what I try, each call to saveToDb throws a constraint violation exception.
What was intended to happen is that when saveToDb fails, the new transaction created by it is rolled back so that the save method can try again.
Is there a way to make this approach work, or should I scrap it and try something else?