我知道这是一个经典问题,但我仍然不知道该怎么做。在 Google App Engine 上,我有一个成员(member)注册表,它使用 jQuery 的 validation 来检查用户名是否存在。
当然存在并发问题:多个用户尝试注册,输入相同的用户名,验证找到可用的用户名,并允许他们大致同时按下“添加”。验证不会检测到这一点。在我的应用程序中,用户名、电子邮件和个人 ID 都应该是唯一的。如何防止以下代码出现并发问题:

member = Member()
member.username = self.request.get('username')
member.Pid = self.request.get('Pid')
member.email = self.request.get('email')
...

最佳答案

由于唯一性约束针对用户名,您必须将其用作数据存储中的键并使用事务。

def txn():
    key = ndb.Key(Member, username)
    member = key.get()
    if member is not None:
        raise CustomAlreadyExistsException(member)  # This will abort txn
    member = Member(
        id=username,
        Pid=self.request.get('Pid'),
        email=self.request.get('email'),
        ...)
    member.put()
ndb.transaction(txn)

这确保只有一个人可以注册一个用户名。

jQuery 助手会检查 ndb.Key(Member, userid).get() 是否给出结果。 GET 不是事务性的。

为了提高客户端在检查可用性后“保留”用户名时的可用性,您可以按照 Daniel 的建议使用 memcached,但我会调用 YAGNI,跳过复杂性,而是让某些人在提交表单后收到验证错误。请注意,memcached 是尽力而为的,并且对任何事情都没有保证。

如果您需要保证多个字段的唯一性,则必须为它们添加模型类并 checkin 跨组 (XG) 事务。
class Pid(ndb.Model):
    member = ndb.KeyProperty()

class Email(ndb.Model):
    member = ndb.KeyProperty()

class Member(ndb.Model):
    pid = ndb.KeyProperty()
    email = ndb.KeyProperty()

    @property
    def pid_value(self):
        return self.pid.id()

    @property
    def email_value(self):
        return self.email.id()

def txn():
    member_key = ndb.Key(Member, username)
    pid_key = ndb.Key(PersonalId, self.request.get('Pid'))
    email_key = ndb.Key(Email, self.request.get('email'))

    member, pid, email = ndb.get_multi([member_key, pid_key, email_key])

    if member is not None or pid is not None or email is not None:
        raise CustomAlreadyExistsException(member, pid, email)  # This will abort txn

    # Create instances referencing each other
    email = Email(key=email_key, member=member_key)
    pid = Pid(key=pid_key, member=member_key)
    member = Member(
        key=member_key,
        pid=pid_key,
        email=email_key,
        ...)
    ndb.put_multi([member, pid, email])

ndb.transaction(txn, xg=True)

关于google-app-engine - 谷歌应用引擎 : concurrent user registrations,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14502948/

10-13 06:30