5

我有一个用 Java 编写的 GAE 项目,我对 HRD 和一个我不知道如何解决的问题有一些想法。

基本上我的系统中有用户。用户由用户 ID、用户名、电子邮件和密码组成。每次创建新用户时,我都想检查是否存在具有相同用户 ID(不应该发生)、用户名或电子邮件的用户。

userid 是关键,所以我认为用这个做一个 get 将是一致的。但是,当我进行查询(并使用过滤器)以查找具有相同用户名或电子邮件的可能用户时,我无法确定结果是否一致。因此,如果有人在几秒钟前创建了具有相同用户名或电子邮件的用户,我的查询可能找不到它。我知道祖先是用来解决这个问题的,但是如果我没有用于查询的祖先怎么办?用户没有父母。

我很高兴听到您对此的想法,以及在这种情况下什么被认为是最佳实践。如果这改变了任何东西,我将使用 Objectify 进行 GAE。

4

4 回答 4

7

我不建议为您的用户实体使用电子邮件或任何其他自然键。用户更改他们的电子邮件地址,并且您不希望在有人更改他们的电子邮件时最终重写数据库中的所有外键引用。

以下是关于我如何解决此问题的简短说明:

https://groups.google.com/d/msg/google-appengine/NdUAY0crVjg/3fJX3Gn3cOYJ

创建一个单独的 EmailLookup 实体,其 @Id 是电子邮件地址的规范化形式(我只是将所有内容都小写 - 技术上不正确,但当用户不小心将 Joe@example.com 大写时会省去很多痛苦)。我的 EmailLookup 如下所示:

@Entity(name="Email")
public class EmailLookup {
    /** Use this method to normalize email addresses for lookup */
    public static String normalize(String email) {
        return email.toLowerCase();
    }

    @Id String email;
    @Index long personId;

    public EmailLookup(String email, long personId) {
        this.email = normalize(email);
        this.personId = personId;
    }
}

我的用户实体中还有一个(未规范化的)电子邮件字段,我在发送出站电子邮件时使用它(保留大小写以防对某人很重要)。当有人使用特定电子邮件创建帐户时,我在 XG 事务中通过密钥加载/创建 EmailLookup 和用户实体。这保证了任何个人电子邮件地址都是唯一的。

相同的策略适用于任何其他类型的独特价值;facebook id、用户名等

于 2012-04-05T16:37:44.837 回答
3

绕过 HRD最终一致性的一种方法是使用get而不是query. 为此,您需要生成自然 ID,例如生成包含您在请求中收到的数据的 ID:电子邮件和用户名。

由于get在 HRD 中具有强一致性,您将能够可靠地检查用户是否已经存在。

例如,一个可读的自然 ID 将是:

String naturalUserId = userEmail + "-" + userName;

注意:实际上电子邮件是独一无二的。因此,这本身就是一个很好的自然 ID。无需向其添加虚构的用户名。

于 2012-04-05T14:12:21.143 回答
-1

您还可以启用跨组事务(请参阅https://developers.google.com/appengine/docs/java/datastore/overview#Cross_Group_Transactions),然后在一个事务中查找用户并创建一个新用户,如果有帮助的话.

于 2012-04-05T14:58:13.497 回答
-1

除非您有其他用途,否则建议避免使用索引字段和查询。这是我之前(Python)使用 key_name 所做的(因为实体 ID 需要是整数)。易于将 key_name 或 id 用于需要链接到用户的其他实体:

username = self.request.get('username')
usernameLower = username.lower()
rec = user.get_by_key_name(usernameLower)
if rec is None:
    U = user(
        key_name = usernameLower,
        username = username,
        etc...)
    U.put()
else:
    self.response.out.write(yourMessageHere)
于 2012-04-05T18:02:04.297 回答