我是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:事务内部的查询必须具有祖先
好的,我理解,但用户没有任何祖先,它是一个根实体。我该怎么办?
答案 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
,则不需要交易