Django:锁定表中的特定行

Kur*_*aum 6 database django locking atomic

我有以下django方法:

def setCurrentSong(request, player):    
  try:
     newCurrentSong = ActivePlaylistEntry.objects.get(
       song__player_lib_song_id=request.POST['lib_id'],
       song__player=player,   
       state=u'QE')
   except ObjectDoesNotExist:
     toReturn = HttpResponseNotFound()
     toReturn[MISSING_RESOURCE_HEADER] = 'song'    
     return toReturn

   try:
     currentSong = ActivePlaylistEntry.objects.get(song__player=player, state=u'PL')
     currentSong.state=u'FN'  
     currentSong.save()
   except ObjectDoesNotExist:  
     pass
   except MultipleObjectsReturned:     
     #This is bad. It means that
     #this function isn't getting executed atomically like we hoped it would be
     #I think we may actually need a mutex to protect this critial section :(
     ActivePlaylistEntry.objects.filter(song__player=player, state=u'PL').update(state=u'FN')

   newCurrentSong.state = u'PL'
   newCurrentSong.save()
   PlaylistEntryTimePlayed(playlist_entry=newCurrentSong).save()
   return HttpResponse("Song changed")
Run Code Online (Sandbox Code Playgroud)

基本上,我希望它是这样的,对于给定的player,只有一个ActivePlaylistEntry在任何给定时间都具有'PL'(播放)状态.但是,我实际上经历过这样的情况:由于连续两次快速调用此方法,我为同一个播放器获得两首歌曲,状态为'PL'.这很糟糕,因为我有其他应用程序逻辑依赖于玩家在任何给定时间只有一首播放歌曲的事实(加上语义上在同一个播放器上同时播放两首不同的歌曲没有意义) .有没有办法让我以原子方式进行更新?只是将该方法作为与on_commit_success装饰器的事务运行似乎不起作用.是否有办法锁定属于特定播放器的所有歌曲的表格?我正在考虑lock在我的模型中添加一个列(布尔字段),或者只是在它上面旋转或暂停线程几毫秒并再次检查,但这些感觉超级hackish和脏.我也在考虑创建一个存储过程,但这不是真正的数据库独立性.

Ign*_*ams 12

1.4中添加了锁定查询.

with transaction.commit_manually():
  ActivePlayListEntry.objects.select_for_update().filter(...)
  aple = ActivePlayListEntry.objects.get(...)
  aple.state = ...
  transaction.commit()
Run Code Online (Sandbox Code Playgroud)

但是你应该考虑重构,以便用一个单独的表ForeignKey来表示"活动"歌曲.