我有以下
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")
基本上,我希望它对于给定的玩家来说,只有一个ActivePlaylistEntry在任何给定时间都具有’PL'(播放)状态.但是,我实际上经历过这样的情况:由于连续两次快速调用此方法,我为同一个播放器获得两首歌曲,状态为’PL’.这很糟糕,因为我有其他应用程序逻辑依赖于玩家在任何给定时间只有一首播放歌曲的事实(加上语义上在同一个播放器上同时播放两首不同的歌曲没有意义) .有没有办法让我以原子方式进行更新?只是使用on_commit_success装饰器作为事务运行该方法似乎不起作用.是否有办法锁定属于特定播放器的所有歌曲的表格?我正在考虑向我的模型添加一个锁定列(布尔字段),或者只是在它上面旋转或暂停线程几毫秒并再次检查,但这些感觉超级hackish和脏.我也在考虑创建一个存储过程,但这不是真正的数据库独立性.
解决方法
在1.4中添加了
Locking queries.
with transaction.commit_manually(): ActivePlayListEntry.objects.select_for_update().filter(...) aple = ActivePlayListEntry.objects.get(...) aple.state = ... transaction.commit()
但是你应该考虑重构,以便使用带有ForeignKey的单独表来表示“活动”歌曲.