使用乐观锁定创建新的数据存储实体(Google App Engine Java/JPA)

使用乐观锁定创建新的数据存储实体(Google App Engine Java/JPA),java,google-app-engine,datanucleus,Java,Google App Engine,Datanucleus,我有一个JPA实体类用户,用户名为@ID,没有父实体组。我需要确保当两个并行事务试图使用相同的用户名持久化一个新的用户时,只有一个被提交,另一个被回滚 例如: User bob = new User("bob"); EntityTransaction transaction = em.getTransaction(); try { transaction.begin(); User u = em.find(User.class, bob.id()); if (u == null)

我有一个JPA实体类用户,用户名为@ID,没有父实体组。我需要确保当两个并行事务试图使用相同的用户名持久化一个新的用户时,只有一个被提交,另一个被回滚

例如:

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();
}
根据数据存储文档,事务遵循乐观锁定方法:

“当事务启动时,App Engine通过检查事务中使用的实体组的上次更新时间来使用乐观并发控制。提交实体组的事务后,App Engine再次检查事务中使用的实体组的上次更新时间。如果它在我们的初始检查后发生了更改,应用程序引擎将抛出一个异常。” ()


在持久化事务之前不存在的新(根)实体时,这会起作用吗?在我的情况下,App Engine会检查另一个事务是否同时持久化了具有相同id的用户吗?如果是,我是否需要一个显式的@Version字段来实现此目的?

来解决一些早该结束的问题:答案是“是”“上述代码应按预期工作。简言之,乐观并发控制机制将使用(根)实体的种类“User”和给定标识符“bob”来比较两个事务中使用的(新)实体组。现在,还可以明确解决创建案例:

当两个或多个事务试图同时更改同一实体组(更新现有实体或创建新实体)时,提交的第一个事务将成功,所有其他事务在提交时将失败


使用JPA,在这种情况下会出现回滚异常。低级API将引发ConcurrentModificationException。如果您使用Objectify(我强烈建议),失败的事务将自动重试。因此,您应该确保,在事务中,您首先检查实体是否存在,除非您想在第二次尝试时覆盖它。

我刚刚遇到,它声称在这种情况下,低级API将抛出ConcurrentModificationException。有人能证实吗,最好也是JPA/JDO?我在发布这篇文章后发现了你的问题,你自己解决了吗?