我正在使用Google App Engine和数据存储区进行客观化。
我正在尝试为用户(Google用户)创建一个帐户,因此我需要检查用户是否存在,如果没有,请为该用户创建一个帐户,但我面临的事实是如果我使用createAccount API方法垃圾邮件
,则会创建两次帐户@ApiMethod(name = "account.google.create")
public Account createGoogleAccount(final User user) throws OAuthRequestException {
if (user == null) {
throw new OAuthRequestException("createAccount: OAuthRequestException<User is not authenticated>");
}
Account alreadyExisting = RObjectifyService.getObjectify().load().type(Account.class).filter("accountId.GOOGLE", user.getUserId()).filter("email", user.getEmail()).first().now();
if (alreadyExisting != null) {
throw new OAuthRequestException("createAccount: OAuthRequestException<Account already exist>");
}
return RObjectifyService.getObjectify().transactNew(new Work<Account>() {
@Override
public Account run() {
Account account = AccountProvider.createAccountFromGoogleProvider(user);
RObjectifyService.save(account);
return account;
}
});
}
我读到我应该使用交易,但我不能,因为如果我在交易中这样做:
RObjectifyService.getObjectify().load().type(Account.class).filter("accountId.GOOGLE", user.getUserId()).filter("email", user.getEmail()).first().now()
我收到错误“在事务中只允许祖先查询”,但我没有看到另一种方法来执行此操作
这是正确的方法吗?
由于
答案 0 :(得分:1)
您需要一个交易,并且您需要一个实体,其主键是您尝试使其唯一的值(即用户名)。
这种模式有点棘手。对它进行了一些讨论here。伪代码的基本思想是:
您可能不希望username
成为User
实体的主键,因此请创建一个单独的Username
实体并混合创建Username
在同一个交易中使用User
。一定要离开Username
实体;这就是保证唯一性的原因。
这个问题(唯一性)实际上是GAE数据存储区等大规模分布式系统中技术上更具挑战性的问题之一。仅当传统的RDBMS是单主系统时,在传统的RDBMS中解决起来很简单,从而对可扩展性和容错性产生影响。 GAE为您提供必要的原语,以强制实现群集范围内的唯一性;它们不是很容易使用。
答案 1 :(得分:0)
在这种情况下,具有强一致性的最佳方法是按键检索实体。