2

我是 GAE 的新手,我对与 DataStore 的事务有一些疑问。

例如,我有一个用户实体,它是在用户在 Facebook 上添加我的应用程序时创建的。我通过 Facebook API 获得了一些属性,但我想为用户添加一个用户名,并且它必须是唯一的。所以在事务范围内我调用这个方法:

def ExistsUsernameToDiferentUser(self, user, username):
    query = User.all()
    query.filter("username", username)
    query.filter("idFacebook != ", user.idFacebook)
    userReturned = query.get()
    return True if userReturned else False

但是 GAE 给了我这个错误:

BadRequestError:事务内部的查询必须有祖先

好的,我明白了,但是用户没有任何祖先,它是一个根实体。我需要做什么?

4

2 回答 2

3

我明白你现在想做什么。

通过强制使用祖先,数据存储会强制您锁定数据存储的一部分(给定祖先下的所有内容),以便您可以保证该部分的一致性。但是,要为所欲为,您本质上需要锁定所有 User 实体以查询某个是否存在,然后创建一个新实体,然后将它们解锁。

你可以这样做,只需创建一个实体,它可以是一个空实体,但要确保它有一个唯一的键(如“user-ancestor”),保存它,并使其成为每个用户实体的祖先。这可能是一个坏主意,因为这会限制您在用户实体上的性能,尤其是在写入方面。每次创建新用户时,都会阻止更新所有用户实体。

我试图说明你需要如何在 HRD 世界中以不同的方式思考交易。由您来构建数据(使用祖先),以便为您的特定应用程序获得良好的性能特征。事实上,您可能不同意我的观点,并说用户实体的更新频率非常低,因此可以将它们全部锁定。

出于说明目的,另一种短视的可能性是根据用户名创建多个祖先。即,每个字母对应一个。然后当你需要创建一个新用户时,你可以根据合适的祖先进行搜索。虽然这是对单一祖先的改进(它好 26 倍),但它仍然限制了你未来的表现。如果您现在知道最终将拥有的用户总数,这可能没问题,但我怀疑您想要数亿用户。

最好的方法是返回到其他建议并将用户名作为密钥。这可以让您获得最佳的可伸缩性,因为通过密钥获取/设置用户实体可以是事务性的,并且不会锁定其他实体,从而限制了您的可伸缩性。

您需要找到一种方法来解决此问题。例如,您在用户名之前获得的任何信息都可以存储在另一个实体中,该实体具有稍后创建的用户的相关字段。或者您可以在通过密钥创建用户实体后将该数据复制到用户实体中,然后删除原始实体。

于 2012-12-04T16:42:19.873 回答
0

如果用户名是唯一的,为什么不将其设为密钥?

class User(db.Model):
    @property
    def username(self):
        return self.key().name()
    ....

User.get_or_insert(username,field1=value1,....)

注意:如果使用 get_or_insert,则不需要事务

于 2012-12-02T05:57:10.303 回答