2012-01-31 53 views
0

有很多關於Django的併發性的話題,但檢查了很多這些之後,我不覺得我已經找到我的答案,當涉及到交易。Django的 - PostgreSQL的:交易和併發

Django的1.3.1版。 Postgresql版本8.4.7。

我的模型非常簡單的版本看起來是這樣的:

def Member(Model): 
    money = PositiveIntegerField(default=0) 
    user = OneToOneField(User, related_name='member', primary_key=True) 

def Bet(Model): 
    total_money = PositiveIntegerField(default=0) 

我也有一個錶款項的會員和BET之間的關係。它不直接與我的問題相關,但它可以幫助我監控它,因爲它不會受到任何併發問題的影響。也就是說,我只需要計算我的表格Money以測試會員的金額和Bet的total_money是否正確。

我不僅可以在桌子上的錢靠雖然,我需要我的領域是正確的,因爲我用他們過濾了很多。

我第一次嘗試爲賭注的功能是這樣的(只是多了很多修改了很多表)。

def bid(user_pk, bet_pk, value): 
    #create Money object 
    member = User.objects.get(user_pk).member 
    member.money = F('money') - value 
    member.save() 
    bet = Bet.objects.get(bet_pk) 
    bet.total_money = F('total_money') + value 
    bet.save() 

這個版本工作得很好,直到我在一次事務中得到第一次崩潰。 我也複製粘貼從我的乾淨所有的測試()投標(功能),因爲我不是真的能在這種情況下使用清潔()或full_clean()(特別是如果賭注提高,後件保存)。

所以我決定給一個嘗試Django的交易。

@transaction.commit_manually 
def bid(user_pk, bet_pk, value): 
    try: 
    #create money object 
    member = User.objects.get(user_pk).member 
    member.money -= value 
    member.clean() 
    member.save() 
    bet = Bet.objects.get(bet_pk) 
    bet.total_money += value 
    bet.clean() 
    bet.save() 
    except: 
    transaction.rollback() 
    raise 
    else: 
    transaction.commit() 

但是沒有在手動事務中使用F()對象的可能性(這是有道理的)。最後我遇到了很多併發問題。

我只看到兩個解決方案:投標()/交易過程中

  • 只有創造貨幣的對象,那麼有一個異步的工人(芹菜?),更新會員和投注的相關領域。

  • 建立出價()/交易(Redis的?)的列表,並作出修改金錢相關領域同步的所有交易。

我是否錯過了一個明顯而簡單的解決方案? 如果不是,您會推薦哪種解決方案使用哪種技術?

回答

1

這項工作?

 
@transaction.commit_on_success 
def bid(user_pk, bet_pk, value): 
    Member.objects.filter(user__pk=user_pk).update(money=F('money') - value) 
    Bet.objects.filter(pk=bet_pk).update(total_money=F('total_money') + value) 

+0

至少它不上升,這已經是從我的版本很好的改善與使用事務+ F對象。非常感謝。對我來說有點晚了(我有很多修改要試試),但明天我會明確嘗試。 – Ashe 2012-01-31 05:42:01

+0

好吧,我的所有測試都是綠色的解決方案,我會很快推出它,並檢查我是否沒有再檢測到任何併發問題。我看到的唯一缺點是: - 我不能使用清潔功能,因爲很明顯的價值不被更新。 - Pre保存和後保存功能不適用於更新(並且我想知道是否更新實際上應該用於修改一個項目) - 我必須刪除我在成員中擁有的money_max字段的更新表。我不認爲你可以用F:update(money_max = max(F('money'),F('money_max')))來寫這樣的東西。我只會寫我自己的SQL查詢。 – Ashe 2012-01-31 19:08:53

+1

我發現了一個辦法做最大的東西: members = Member.objects.filter(user__id = member_pk) members.update(money = F('money') - value) members.filter(money_max__lt = F('錢 '))。更新(money_max = F(' 錢')) – Ashe 2012-01-31 21:57:24