下面是一个具有潜在竞争条件的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可以使用什么样的锁定机制来处理类似的情况?

推荐答案

Django 1.4+支持select_for_update,在早期版本中,您可以执行原始SQL查询,例如select ... for update,这取决于底层数据库是否会锁定该行,不能进行任何更新,您可以对该行做任何您想做的事情,直到事务结束.例如:

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()

Database相关问答推荐

在使用FT.AGGREGATE聚合数据时,如何在Redis上解析ISO 8601时间?

使用mongoose 在嵌套对象中查找特定字段

获取总和列的比率

从 GCP 机密管理器中读取 .DER 值并将其保存到 .DER 文件

MYSQL CASE 语句多条件

PostgreSQL 嵌套 INSERTs / WITHs 用于外键插入

如何在我的 Rails 应用程序中避免竞争条件?

有没有办法为 2 个具有不同包名称的应用程序提供 1 个 Firebase 数据库?

MS Access:如何在 VBA 中压缩当前数据库

如何在运行时备份嵌入式 H2 数据库引擎?

在 PostgreSQL 上获取数据库创建日期

从 XML 读取数据

返回 DataSet/DataTable 的 PowerShell 函数中的奇怪行为

SQL查询7天前的数据

friendship数据库模式

不带 WHERE 子句的 UPDATE 查询

获取数据库路径

如何一次插入1000行

在具有所需 ForeignKey 引用的 Django (1.8) 应用程序之间移动模型

Windows phone 7 的本地 Sql 数据库支持