Python Django';s Model.save()修改不需要的列
最近,我发现Django ORM的Python Django';s Model.save()修改不需要的列,python,sql,django,Python,Sql,Django,最近,我发现Django ORM的Model.save()执行一个SQL来默认更新'ALL'列,即使没有修改任何内容。 这确实让我担心,因为我所做的任何更改都有可能被其他Model.save()过程设置回原始值 例如,我有一个型号订单。有两个并发进程(P1,P2)在处理它。首先,P1选择一行: # P1 order = Order.objects.get(pk=10000) 然后,P2选择同一行并更新状态列:(以下语句可以封装在事务中,甚至可以封装在可序列化的事务中,但这无法解决问题。) 之后
Model.save()
执行一个SQL来默认更新'ALL'列,即使没有修改任何内容。
这确实让我担心,因为我所做的任何更改都有可能被其他Model.save()过程设置回原始值
例如,我有一个型号订单
。有两个并发进程(P1,P2)在处理它。首先,P1选择一行:
# P1
order = Order.objects.get(pk=10000)
然后,P2选择同一行并更新状态
列:(以下语句可以封装在事务中,甚至可以封装在可序列化的事务中,但这无法解决问题。)
之后,P1更新其他一些琐碎的列:
# P1
order.xxx = xxx # update some other trivial column
order.save() # This would set the `status` back to UNPAID !!!
订单。状态
将被设置回未付款
,这不是我想要的
我知道我可以使用save(update_fields=…)
,选择_for_update()
,过滤器(…).update(…)
,可序列化事务,或在P1上显式锁定来防止此问题。
但问题是:在整个项目中的所有Model.save()
语句上使用它们是荒谬的。此外,即使我在我的项目代码中这样做,也有一些其他代码在这样做(Django Admin、ModelForm…)
我是否应该重写Model.save()
以仅更新那些修改过的字段
(对我来说,这似乎是一个严重的问题。还是我做错了什么?正如其他人在评论中所说的,你有一种经典的类型。在Django有一些方法可以解决这个问题。你已经提到了其中一些,但根据我的经验,它们不能被认为是安全的。我强烈建议您观看名为Immutable Django
,并开始朝这个方向挖掘
基本上,您可以在模型中添加某种类型的version
列,并在每次保存时增加该列,并与现有列进行比较。如果新版本相同或更少,则已保存一个-您正在尝试保存非实际条目。您只需要一列即可发生类似的竞争条件:
# Process 1
account = Account.objects.get(pk=1)
account.balance += 1000
# Process 2
account = Account.objects.get(pk=1)
account.balance -= 10
account.save()
# Process 1
account.save()
现在,流程2的余额扣减已丢失。您必须使用select\u for\u update
确保写入一致。即使只保存“脏”字段,并将其设为默认值,这种情况仍然会发生。之所以发生,是因为P1
不知道您更改了P2
的状态
属性。为什么需要两个不同的引用来引用相同的顺序
?@DeepSpace我认为P1
和P2
是不同的进程。@DeepSpace是的,它们是不同的进程。例如,一名员工正在使用Django Admin修改该订单(P1
),一名客户正在付款(P2
)。因此,这是一个竞争条件,但您已经说明了解决此问题的各种方法。
# Process 1
account = Account.objects.get(pk=1)
account.balance += 1000
# Process 2
account = Account.objects.get(pk=1)
account.balance -= 10
account.save()
# Process 1
account.save()