2

私はGAEを初めて使用し、データストアとのトランザクションについていくつか質問があります。

たとえば、ユーザーが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-ancestor"など)があることを確認して保存し、すべてのUserエンティティの祖先にします。これは、ユーザーエンティティ、特に書き込みでのパフォーマンスを制限するため、おそらく悪いアイデアです。新しいユーザーが作成されるたびに、すべてのユーザーエンティティが更新されなくなります。

私は、HRDの世界でトランザクションについて少し違った考え方をする必要があることを説明しようとしています。特定のアプリケーションで優れたパフォーマンス特性が得られるように、(祖先を使用して)データを構造化するのはあなた次第です。実際、あなたは私に同意せず、ユーザーエンティティが更新される頻度が非常に低いため、すべてをロックしても問題ないと言うかもしれません。

説明のために、もう1つの近視眼的な可能性は、ユーザー名に基づいて複数の祖先を作成することです。つまり、アルファベットの文字ごとに1つです。次に、新しいユーザーを作成する必要がある場合は、適切な祖先に基づいて検索できます。これは単一の祖先を持つことからの改善ですが(26倍優れています)、それでも前もって将来のパフォーマンスを制限します。最終的にユーザーの総数がわかっていれば、これで問題ないかもしれませんが、何億人ものユーザーが必要だと思います。

最善の方法は、他の提案に戻って、ユーザー名をキーにすることです。これにより、最高のスケーラビリティが可能になります。これは、キーによるユーザーエンティティの取得/設定がトランザクションであり、他のエンティティをロックダウンせず、スケーラビリティが制限されるためです。

これを回避するためにアプリケーションを動作させる方法を見つける必要があります。たとえば、ユーザー名の前に取得した情報はすべて、後で作成されるユーザーへのRelatedFieldを持つ別のエンティティに保存できます。または、ユーザーエンティティがキーで作成された後でそのデータをユーザーエンティティにコピーしてから、元のエンティティを削除することもできます。

于 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 に答える