In Google App Engine, how do I avoid creating duplicate entities with the same attribute?
I am trying to add a transaction to keep from creating two entities with the same attribute. In my application, I am creating a new Player each time I see a new Google user logged in. My current implementation occasionally creates duplicate players when multiple json calls are made by a new Google user within a few milliseconds. When开发者_开发问答 I add the transaction like the one commented out here, I get various errors. What is the easiest way to ensure that I never create two player entities with the same user_id?
def get_player_from_user(self, user_id):
player = Player.all().filter('user_id =', user_id).get()
if not player:
#This can result in duplicate players with the same user_id being created.
player = self.create_new_player(user_id)
#This is what I'm trying to do.
#player = db.run_in_transaction(self.create_new_player, user_id=user_id)
return player
def create_new_player(self,user_id):
#Check one more time for an existing user_id match.
player = Player.all().filter('user_id =', user_id).get()
if player:
return player
player = Player()
player.user_id = user.user_id()
player.put()
return player
Use the username (or other identifier) as the key name, and use get_or_insert to transactionally create a new entity or return the existing one. Sahid's code won't work, because without a transaction, a race condition is still possible.
Maybe you can use key name and get_by_key_name is better than filter.
def create_new_player(self,user_id):
key_name = "player/%s" % user_id
player = Player.get_by_key_name (key_name)
if player is None:
player = Player (key_name=key_name, user_id=user_id)
player.put ()
return player
With the last comment of Nick, i have updated my code, so the better solution is:
def create_new_player(self,user_id):
key_name = "player/%s" % user_id
player = Player.get_or_insert (key_name=key_name, user_id=user_id)
return player
精彩评论