7

У меня есть функция, которая выполняет несколько запросов в одном наборе данных, и я хочу, чтобы все запросы отображали точно такие же данные.В Django, как добиться повторяемости чтения для транзакции?

С точки зрения SQL это означает, что уровень изоляции REPEATABLE READ для баз данных, которые его поддерживают. Я не против иметь более высокий уровень или даже полную блокировку, если база данных не способна.

Насколько я вижу, это не тот случай. То есть если я бегу что-то вроде этого кода в одной оболочке Python:

with transaction.atomic(): 
    for t in range(0, 60): 
     print("{0}: {1}".format(t, MyModel.objects.count())) 
     time.sleep(1) 

Как только я MyModel.objects.create(...) в другой, значение, обнаруженное за счет увеличения контура проточной немедленно. Именно этого я и хочу избежать. Дальнейшие тесты показывают, что поведение соответствует уровню READ COMMITTED, который слишком слаб для моих вкусов.

Я также хочу подчеркнуть, что я хочу более строгого уровня изоляции только для одной функции, а не для всего проекта.

Каковы мои лучшие варианты для достижения этой цели?

В моем конкретном случае единственной базой данных, о которой я забочусь, является PostgreSQL 9.3+, но мне также нужна некоторая совместимость с SQLite3, и в этом случае даже полная блокировка всей базы данных в порядке со мной. Но, очевидно, чем более общим является решение, тем более предпочтительным оно является.

+0

кэширование этих метаданных является приемлемым подходом? –

+0

К сожалению, нет. Запросы, которые я вычисляю по разным статистическим данным по необработанным данным событий, и иметь согласованный вид, мне придется вытащить весь набор данных в памяти, чего я действительно не хочу делать. – drdaeman

ответ

6

Вы правы, уровень изоляции транзакций по умолчанию в postgres является ЧИТАЕМОЙ КОМИТЕТОМ. Вы можете легко изменить его в настройках, чтобы проверить, будет ли она соответствовать вашим потребностям: https://docs.djangoproject.com/en/1.8/ref/databases/#isolation-level

Также я сомневаюсь, что вы будете сталкиваться некоторые проблемы с производительностью, потому что Postgres работает очень эффективно при работе с транзакциями. Даже в режиме SERIALIZABLE. Также mysql имеет REPEATABLE READ уровень изоляции по умолчанию, и, как мы видим, это не повредит производительности.

В любом случае вы можете установить режим изоляции вручную всякий раз, когда вам нужно, как это: http://initd.org/psycopg/docs/extensions.html#isolation-level-constants

Чтобы установить пользовательский уровень изоляции транзакций, вы можете попробовать что-л, как:

from django.db import connection 

with transaction.atomic(): 
    cursor = connection.cursor() 
    cursor.execute('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ') 
    # logic 

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

+0

Спасибо за ответ. Раньше у меня были проблемы с производительностью (я думаю, что это было около пяти лет назад) и изменение уровня изоляции по умолчанию от SERIALIZABLE до READ COMMITTED (который был проектом, отличным от Django) оказал разумное влияние на производительность. Возможно, это был только мой конкретный случай, или я попал в какую-то ошибку. В любом случае, я как бы неохотно устанавливаю слишком строгий уровень изоляции во всем мире и хотел бы знать, есть ли способ изменить это только на время выполнения одной функции или кодового блока. Или знать, что это просто невозможно, потому что что-то в дизайне ORM предотвращает это. – drdaeman

+0

Конечно, есть сценарии, где жесткие режимы изоляции переполнены. В любом случае postgres сделают все возможное :) Настройка некоторого уровня изоляции не по умолчанию для определенных частей вашего кода абсолютно в порядке.Использование одного и того же во всем проекте просто более последовательное, поскольку оно гарантирует, что вы, по крайней мере, не забудете сделать это где-нибудь. Обновлен ответ с образцом кода. – alTus

+1

проблема заключается в том, что перед любыми запросами вы должны называть 'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ', и это не так просто сделать в Django. –

Смежные вопросы