用于注册验证的 GAE 数据库的强一致性查询

Posted

技术标签:

【中文标题】用于注册验证的 GAE 数据库的强一致性查询【英文标题】:Strongly Consistency Queries with GAE database for register validation 【发布时间】:2012-12-15 21:44:24 【问题描述】:

我正在尝试为用户创建一个简单的注册。为了使该注册保持一致,我不能允许使用相同的用户名注册两个用户,因为默认查询的最终一致性。我知道即使有相当大的流量发生这种情况的几率几乎是 0,我希望我的实现是可靠的。我已经实现了应该是强一致的祖先查询,但是当我发布我的应用程序并对其进行测试时,如果我的时间正确,我可以让它注册 2 个具有相同用户名的用户。

def user_parent(group = 'default'):
key = ndb.Key('users', group)
return key

class User(ndb.Model):
    username = ndb.StringProperty(required = True)
    email = ndb.StringProperty(required = True)
    password = ndb.StringProperty(required = True)

@classmethod
def register(cls, username, password, email):
    return User(parent = user_parent(),
                username = username,
                password = password,
                email = email)

@classmethod
def by_name(cls, name):
    return User.query(User.username == name, ancestor = user_parent()).get()

@classmethod
def by_id(cls, uid):
    return User.get_by_id(uid, parent = user_parent()) 

@classmethod
def by_email(cls, email):
    logging.error(User.query(User.email == email, ancestor = user_parent()).get())
    return User.query(User.email == email, ancestor = user_parent()).get()

@classmethod
def login(cls, user, password):
    u = cls.by_name(user)
    if u and u.password == password:
        return u

我使用 reg_submit 来执行 ajax 请求,我对编程很陌生,并且怀疑这是解决它的最佳解决方案,但我的想法是在这里我通过对 User 模型类的调用进行验证。

    if reg_submit == 'True':
        reg_email = self.request.get('reg_email')
        reg_user = self.request.get('reg_user')
        reg_password = self.request.get('reg_password')
        reg_verify = self.request.get('reg_verify')

        valid = True
        if not valid_usr(reg_user):
            valid = False
            self.write('user')
            return
        if not valid_mail(reg_email):
            valid = False
            self.write('mail')
            return

        if User.by_email(reg_email):
            valid = False
            self.write('mail')
            return

        if User.by_name(reg_user):
            valid = False
            self.write('user')
            return

        if not valid_pass(reg_password):
            valid = False

        if reg_password != reg_verify:
            valid = False

        if valid:
            t = User.register(reg_user, reg_password, reg_email)
            t.put()
            self.login(t)
            self.redirect('/')

通过使查询具有强一致性,我理解的是,在复制我的数据库的每台机器都将更新之前,所述查询不会执行。

如果两个用户同时注册,使用相同的用户名,其中一个用户不能这样做,我如何实现强一致性查询。

【问题讨论】:

【参考方案1】:

您需要运行检查查询并放入事务中。使用 NDB 执行此操作的文档是 here。

【讨论】:

【参考方案2】:
Model.get_or_insert (key_name, **kwds)

尝试使用给定键获取模型类型的实体 姓名。如果存在,get_or_insert() 会简单地返回它。如果没有 存在,具有给定种类、名称和 kwds 参数的新实体 被创建、存储和返回。

get 和随后的(可能的)put 操作被包装在一个 事务以确保原子性。这意味着 get_or_insert() 将 从不覆盖现有实体,如果 并且仅当不存在具有给定种类和名称的实体时。

Get Or Insert。

使用用户名作为key_name。设置您的模型,使其具有默认值,说“new = True”,并检查当您取回模型时它是否刚刚创建或在您要求时已经存在。当您配置模型并将其保存回来时,设置“new = False”。

【讨论】:

我决定进行交易,因为我必须同时验证用户名和电子邮件(据我所知,这种方法只需要一个 key_name)以避免数据翻倍在这两个领域。我相信这种方法将来会派上用场,所以感谢您的回复。 没问题。实际上 get_or_insert 在事务中运行,实际上只是一种速记方法,但我明白你的意思。

以上是关于用于注册验证的 GAE 数据库的强一致性查询的主要内容,如果未能解决你的问题,请参考以下文章

如何确保 GAE 上的 MemCache 和 Datastore 之间的一致性?

数据库的强一致性和弱一致性

基于MySQL和DynamoDB的强一致性分布式事务实践

就够了!

validate中remote的用法

分布式架构之「 Paxos协议」