I have a JPA entity class User with a username @ID and no parent entity group. I need to make sure that when two parallel transactions try to persist a new User with the same username, only one is committed and the other one is rolled back.
Example:
User bob = new User("bob");
EntityTransaction transaction = em.getTransaction();
try {
transaction.begin();
User u = em.find(User.class, bob.id());
if (u == null) {
em.persist(bob);
} else {
// identical user already existed before the transaction
throw new UserExistsException();
}
transaction.commit();
} catch (RollbackException e) {
// identical user was created during the transaction
throw new UserExistsException();
}
According to the Datastore docs, transactions follow an optimistic locking approach:
"When a transaction starts, App Engine uses optimistic concurrency control by checking the last update time for the entity groups used in the transaction. Upon commiting a transaction for the entity groups, App Engine again checks the last update time for the entity groups used in the transaction. If it has changed since our initial check, App Engine throws an exception." (https://developers.google.com/appengine/docs/java/datastore/transactions)
Will this work when persisting new (root) entities, which did not exist before the transaction? In my case, would App Engine check whether another transaction has meanwhile persisted a User with the same id? If so, do I need an explicit @Version field for that purpose?