根实体中的GAE事务

时间:2012-12-01 18:24:21

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

我是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:事务内部的查询必须具有祖先

好的,我理解,但用户没有任何祖先,它是一个根实体。我该怎么办?

2 个答案:

答案 0 :(得分:3)

我看到你现在要做的事情。

通过强制使用祖先,数据存储区会强制您锁定数据存储区的一部分(给定祖先下的所有内容),这样您就可以保证该部分的一致性。但是,要执行您想要的操作,您基本上需要锁定所有用户实体以查询是否存在某个实体,然后创建一个新实体,然后解锁它们。

你可以这样做,只需创建一个实体,它可以是一个空实体,但要确保它有一个唯一的密钥(如“user-ancestor”),保存它,并使其成为每个User实体的祖先。 这可能是一个糟糕的想法,因为这会限制您在用户实体上的表现,特别是在写入时。每次创建新用户时,都会阻止更新所有用户实体。

我试图说明在HRD世界中你需要如何区别地考虑交易。由您来构建数据(使用祖先),以便为特定应用程序获得良好的性能特征。事实上,您可能不同意我的意见,并说用户实体将很少更新,可以将它们全部锁定。

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

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

您需要找到一种方法来处理您的应用程序。例如,在用户名之前获得的任何信息都可以存储在另一个实体中,该实体具有稍后创建的User的RelatedField。或者,您可以在按键创建用户实体后将该数据复制到用户实体,然后删除原始实体。

答案 1 :(得分:0)

如果用户名是唯一的,为什么不把它作为密钥呢?

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

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

注意:如果使用get_or_insert

,则不需要交易