以下是具有潜在竞争条件的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()
Run Code Online (Sandbox Code Playgroud)
竞争条件应该是相当明显的:用户可以两次发出此请求,并且应用程序可能user = request.user同时执行,导致其中一个请求覆盖另一个请求.
假设函数calculate_points相对复杂,并且基于各种奇怪的东西进行计算,这些东西不能放在一个单独的update并且很难放入存储过程中.
所以这是我的问题:django可以使用哪种锁定机制来处理类似的情况?
我有一个简单的模型:
class InvitationRequest(models.Model):
email = models.EmailField(max_length=255, unique=True)
Run Code Online (Sandbox Code Playgroud)
一个简单的模型形式:
class InvitationRequestForm(forms.ModelForm):
class Meta:
model = InvitationRequest
Run Code Online (Sandbox Code Playgroud)
现在,假设我尝试以标准方式处理它:
form = InvitationRequestForm(request.POST)
if form.is_valid():
form.save()
Run Code Online (Sandbox Code Playgroud)
存在竞争条件,因为验证执行简单SELECT查询以确定是否已经存储了这样的电子邮件,并且如果一切正常,则它继续进行form.save().如果有一个并发进程在同一时刻执行相同操作,则两个表单都将验证,并且两个进程都将调用,form.save()因此一个将成功,另一个将失败导致IntegrityError.
处理这个问题的标准方法是什么?
我希望在表单对象中有一个标准错误,因此我可以将其传递给模板并通知用户该问题.
我知道:
SERIALIZABLE事务包装所有东西(在MySQL中,因为它执行下一个键锁定每次选择)Model._perform_unique_checks并使其使用select_for_update(由于下一个键锁定,与MySQL一起使用)这些解决方案都没有吸引力,我也使用PostgreSQL,它与MySQL在这个领域不同.