Django - Хранение сохраняет () базирующиеся короткие транзакции

Как django образцовое сохранение () методы не ленивы, и поскольку хранение коротких транзакций является общей хорошей практикой, должен сохранять быть предпочтительно задержанным в конец блоков транзакции?

Как пример, был бы пример кода B содержать транзакцию, открытую в течение меньшего количества времени, чем пример кода ниже?

Пример кода 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()

5
задан Community 23 May 2017 в 11:47
поделиться

2 ответа

Django по умолчанию работает с открытой транзакцией, которую он автоматически фиксирует при вызове любой встроенной функции модели, изменяющей данные. В случае декораторов commit_on_success или commit_manually, django фиксирует не при сохранении(), а при успешном завершении выполнения функции или по команде 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, которую для новых экземпляров можно получить только после первого сохранения(), попробуйте разбить ваш поток на разумно большие рабочие блоки, чтобы не держать транзакцию открытой в течение долгих минут.

Также обратите внимание, что длинные транзакции - это не всегда плохо. Если ваше приложение является единственным объектом, изменяющим базу данных, это может быть вполне нормально. Однако вам следует проверить конкретную конфигурацию вашей базы данных, чтобы узнать лимит времени для транзакций (или неработающих транзакций).

1
ответ дан 15 December 2019 в 00:48
поделиться

Я не уверен, но вот моя теория - я бы подумал, что ваш декоратор commit_manually начнет новую транзакцию, а не создаст новую транзакцию, когда вы выполните первое сохранение. Итак, моя теория заключается в том, что образец кода B будет держать транзакцию открытой дольше, поскольку он должен дважды перебирать список моделей.

Опять же, это всего лишь теория - и это также может зависеть от того, какую СУБД вы используете, когда начинается фактическая транзакция (другая теория).

3
ответ дан 15 December 2019 в 00:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: