这是带有潜在竞争条件的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同时执行,从而导致其中一个请求覆盖另一个请求。
user = request.user
假设函数calculate_points相对复杂,并且基于无法放置在单个update存储过程中并且难以放置在存储过程中的各种奇怪的东西进行计算。
calculate_points
update
所以这是我的问题:django可使用哪种锁定机制来处理类似的情况?
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()