2012-01-31 55 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