一尘不染

Django的比赛条件

django

这是带有潜在竞争条件的Django视图的简单示例:

# myapp/views.py
from django.contrib.auth.models import User
from my_libs import calculate_points

def add_points(request):
    user = request.user
    user.points += calculate_points(user)
    user.save()

竞争条件应该非常明显:用户可以两次发出此请求,并且该应用程序可能user = request.user同时执行,从而导致其中一个请求覆盖另一个请求。

假设函数calculate_points相对复杂,并且基于无法放置在单个update存储过程中并且难以放置在存储过程中的各种奇怪的东西进行计算。

所以这是我的问题:django可使用哪种锁定机制来处理类似的情况?


阅读 372

收藏
2020-04-01

共1个答案

一尘不染

Django 1.4+支持select_for_update,在早期版本中,你可以执行原始SQL查询,例如select … forupdate,取决于基础数据库,该行将锁定该行免受任何更新的影响,你可以对该行执行任何操作,直到事务结束。例如

from django.db import transaction

@transaction.commit_manually()
def add_points(request):
    user = User.objects.select_for_update().get(id=request.user.id)
    # you can go back at this point if something is not right 
    if user.points > 1000:
        # too many points
        return
    user.points += calculate_points(user)
    user.save()
    transaction.commit()
2020-04-01