Какие конкретные исключения представляют сбой сериализации, когда Django использует сериализуемый уровень изоляции транзакции с postgresql? - PullRequest
0 голосов
/ 21 сентября 2018

Иногда для операций с базой данных в Django желательно использовать более высокий уровень изоляции, чем по умолчанию "read commit". Документы предупреждают , что:

При более высоких уровнях изоляции ваше приложение должно быть готово обрабатывать исключения, возникающие при сбоях сериализации.

Но какие конкретноисключения указывают на сбой сериализации, в отличие от какой-либо другой проблемы с запросом или транзакцией?

Простой механизм повторной попытки после сбоя сериализации может выглядеть примерно так:

for retries in range(0, 3):
    try:
        with transaction.atomic():
            MyModel.objects.update(foo='bar')
    except StuffHappened:
        continue
    else:
        break

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

Django имеет множество исключений базы данных и исключений транзакций .Может ли один / некоторые из них представлять сбои сериализации?

Я специально заинтересован в postgresql для этого.

1 Ответ

0 голосов
/ 21 сентября 2018

Хм, хороший вопрос.Документация подразумевает, что соответствующее исключение будет TransactionManagementError:

TransactionManagementError возникает для всех проблем, связанных с транзакциями базы данных.

Однако исходный код дает четкое представление о том, что это не так:

class TransactionManagementError(ProgrammingError):
    """Transaction management is used improperly."""
    pass

Обратите внимание, что это ProgrammingError, что действительноиспользуется для обозначения ошибки программиста (то есть «используется неправильно»).

Если мы посмотрим на документацию для psycopg (адаптер Python, используемый для поддержки PostgreSQL), мы увидим, что он вызовет psycopg2.extensions.TransactionRollbackError:

исключение psycopg2.extensions.TransactionRollbackError (подклассы OperationalError)

Ошибка, вызывающая откат транзакции (взаимоблокировки, ошибки сериализации и т. Д.).

Но что Джанго делает с этим?Ну, как указано здесь , он оборачивает стандартные исключения Python DB API 2.0 в эквивалентах Django и устанавливает атрибут __cause__ в исходное исключение.Таким образом, следующая, вероятно, самая конкретная проверка, которую вы можете сделать:

from django.db import OperationalError
from psycopg2.extensions import TransactionRollbackError

for retries in range(0, 3):
    try:
        with transaction.atomic():
            MyModel.objects.update(foo='bar')
    except OperationalError as e:
        if e.__cause__.__class__ == TransactionRollbackError:
            continue
        else:
            raise            
    else:
        break

В зависимости от сведений об ошибках, обнаруженных в PostgreSQL (доступных через e.__cause__.diag), можно написатьеще более конкретный тест.

Как правило, в документации Python DB API 2.0 указывается, что OperationalError действительно является правильным типом исключения для проблем транзакций, так что отлов этого, надеюсь, будет разумнымэффективное решение, не зависящее от базы данных.

...