【问题标题】:Objectify: Handle race condition to prevent duplicate account creationObjectify:处理竞争条件以防止重复创建帐户
【发布时间】:2015-02-17 00:44:41
【问题描述】:

我将 Google App Engine 和 Datastore 与 objectify 一起使用。

我正在尝试为用户(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()

我收到一个错误“事务中只允许祖先查询”,但我没有看到其他方法

这是正确的做法吗?

谢谢

【问题讨论】:

    标签: google-app-engine google-cloud-datastore objectify


    【解决方案1】:

    您需要一个事务,并且您需要一个实体,其主键是您试图使其唯一的值(即用户名)。

    模式有点棘手。对此有一些讨论here。伪代码的基本思想是:

    • 开始交易
    • 加载具有唯一 PK 的实体
    • 如果有实体
      • 中止并返回重复错误
    • 其他
      • 创建具有唯一 PK 的实体(+您需要的任何额外工作)
      • 提交事务
      • 如果提交失败
        • 中止并返回重复错误
      • 其他
        • 一切都很棒!

    您可能不想将username 设为User 实体的主键,因此请创建一个单独的Username 实体并将UsernameUser 的创建混合在同一个事务中。一定要留下Username 实体;这就是唯一性的保证。

    这个问题(唯一性)实际上是在像 GAE 数据存储这样的大规模分布式系统中更具技术挑战性的问题之一。只有当传统的 RDBMS 是单主系统时,在传统的 RDBMS 中才能轻松解决,从而影响可伸缩性和容错性。 GAE 为您提供了强制执行集群范围唯一性的必要原语;它们只是不是超级好用。

    【讨论】:

    • 是的,我了解问题所在,您的解决方案有效,谢谢!
    【解决方案2】:

    在这种情况下,获得强一致性的最佳方法是按键检索实体。

    【讨论】:

    • 我不确定如何在不进行查询的情况下获取密钥?也许您打算将电子邮件用作 id?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    • 2016-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多