python - Django 的 select_for_update 方法是否与 update 方法一起使用?
问题描述
我正在使用的 Django 2.2的文档提供了以下示例用法select_for_update
:
from django.db import transaction
entries = Entry.objects.select_for_update().filter(author=request.user)
with transaction.atomic():
for entry in entries:
...
使用这种方法,可能会改变分配给的模型实例entry
并调用save
它们。
在某些情况下,我更喜欢下面的替代方法,但我不确定它是否会与select_for_update
.
with transaction.atomic():
Entry.objects.select_for_update().filter(author=request.user).update(foo="bar", wobble="wibble")
该文档指出,在评估查询集时会创建锁,因此我怀疑该update
方法是否可行。据我所知update
,只是执行一个UPDATE ... WHERE
查询,SELECT
之前没有。但是,如果对 Django ORM 的这方面更有经验的人能证实这一点,我将不胜感激。
第二个问题是,如果一个人对锁定的行进行单个UPDATE
查询,那么锁是否甚至增加了针对竞争条件的任何保护。(我进入这个思路是因为我正在重构在更新单行的两列的值时使用锁的代码。)
解决方案
据我所知,更新只是执行一个 UPDATE ... WHERE 查询,之前没有 SELECT
对,那是正确的。您可以通过查看实际查询来确认这一点。以规范的 django 教程“polls”应用为例:
with transaction.atomic():
qs = polls.models.Question.objects.select_for_update().all()
qs.update(question_text='test')
print(connection.queries)
# {'sql': 'UPDATE "polls_question" SET "question_text" = \'test\'', 'time': '0.008'}
因此,正如您所料,没有SELECT
.
不过,确保获得锁就像做任何事情来评估查询集一样简单。
with transaction.atomic():
qs = polls.models.Question.objects.select_for_update().all()
list(qs) # cause evaluation, locking the selected rows
qs.update(question_text='test')
print(connection.queries)
#[...
# {'sql': 'SELECT "polls_question"."id", "polls_question"."question_text", "polls_question"."pub_date" FROM "polls_question" FOR UPDATE', 'time': '0.003'},
# {'sql': 'UPDATE "polls_question" SET "question_text" = \'test\'', 'time': '0.001'}
#]
第二个问题是,如果一个人对锁定的行进行单个 UPDATE 查询,那么锁是否甚至增加了针对竞争条件的任何保护
一般来说,是的。在特定情况下是否有必要取决于您担心哪种竞争条件。例如,锁将防止另一个事务可能尝试更新同一行的竞争条件。
根据更新/竞争条件的性质,也可以在没有锁的情况下避免竞争条件。有时一笔交易就足够了,有时则不然。您还可以使用在数据库服务器端评估的表达式来防止竞争条件(例如使用Django 的F()
表达式)。
还有其他考虑因素,例如您的数据库方言、隔离级别等。
关于竞争条件思想的附加参考:PostgreSQL 反模式:读-修改-写周期(存档)
推荐阅读
- python-3.x - 停止由另一个事件处理的事件
- azure - SignalR Azure 新帐户不会出现集成问题
- node.js - 当我尝试访问 localhost 时,node.js 应用程序中的 get() 没有被调用
- javascript - Commander 包未正确解析所有选项
- mysql - MySql 计算分组字段百分比并显示在一行
- makefile - 设置变量以用于不同的 make 目标
- assembly - 无论如何让GCC生成额外的NOP指令以将指令执行与某个块大小对齐?
- python - 如何在 pytorch 或 numpy 中对分数/概率图进行聚类并获取模式(可变数字)
- reactjs - Tensorflow.js 裁剪图像返回零张量
- compiler-construction - 在 LLVM .ll IR 中显示额外的文本消息