作为django模型的save()方法are not lazy,并且由于保持交易简短是一般的良好做法,应该优先将保存推迟到交易块的末尾吗?
作为一个例子,代码样本B是否会保持事务打开的时间比下面的代码示例A少?
代码示例A:
from django.db import transaction
from my_app.models import MyModel
@transaction.commit_on_success
def model_altering_method():
for inst in MyModel.objects.all()[0:5000]:
inst.name = 'Joel Spolsky'
# Some models independent time consuming operations...
inst.save()
代码示例B:
from django.db import transaction
from my_app.models import MyModel
@transaction.commit_on_success
def model_altering_method():
instances_to_save = []
for inst in MyModel.objects.all()[0:5000]:
inst.name = 'Joel Spolsky'
# Some models independent time consuming operations...
instances_to_save.append(inst)
for inst in instances_to_save:
inst.save()
答案 0 :(得分:3)
我不确定,但这是我的理论 - 我认为你的commit_manually装饰器将开始一个新的事务,而不是在你第一次保存时出现新的事务。所以我的理论是代码样本B会使事务保持更长时间,因为它必须遍历模型列表两次。
同样,这只是一个理论 - 它还可能取决于您在实际交易开始时使用的DBMS(另一种理论)。
答案 1 :(得分:1)
Django的默认行为是使用open事务运行,当调用任何内置的数据更改模型函数时,它会自动提交。在commit_on_success或commit_manually装饰器的情况下,django不会在save()上提交,而是在函数执行成功完成时或在transaction.commit()命令上提交。
因此,优雅的方法是在可能的情况下将事务处理代码与其他耗时的代码分开:
from django.db import transaction
from my_app.models import MyModel
@transaction.commit_on_success
def do_transaction(instances_to_save):
for inst in instances_to_save:
inst.save()
def model_altering_method():
instances_to_save = []
for inst in MyModel.objects.all()[0:5000]:
inst.name = 'Joel Spolsky'
# Some models independent time consuming operations...
instances_to_save.append(inst)
do_transaction(instances_to_save)
如果设计不可行,例如你需要instance.id信息,对于新实例,你只能在第一次save()之后获得,尝试将你的流程分解为合理大小的工作单元,以免长时间保持交易开放。
另请注意,长时间交易并不总是坏事。如果您的应用程序是修改数据库的唯一实体,那么它实际上可以正常。但是,您应该检查数据库的特定配置,以查看事务(或空闲事务)的时间限制。