当 Django 在 postgresql 中使用可序列化事务隔离级别时,哪些特定异常表示序列化失败?

What specific exceptions represent a serialization failure when Django is using serializable transaction isolation level with postgresql?

有时需要为 Django 中的数据库操作使用比默认 "read committed" 更高的隔离级别。 The docs warn 那:

Under higher isolation levels, your application should be prepared to handle exceptions raised on serialization failures.

但哪些特定异常表示序列化失败,与查询或事务的其他问题相比?

序列化失败后的简单重试机制可能如下所示:

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

哪些特定异常应该替换 StuffHappened 以便只有序列化失败而不是其他异常导致重试?

Django 有多种Database Exceptions and Transaction Exceptions。 one/some 可能表示序列化失败?

为此我对 postgresql 特别感兴趣。

嗯,问得好。该文档暗示适当的例外是 TransactionManagementError:

TransactionManagementError is raised for any and all problems related to database transactions.

然而,source code 给出了一个强有力的线索,表明它不是:

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

请注意,这是一个ProgrammingError,它确实用于指示程序员错误(即"used improperly")。

如果我们查看 psycopg(用于 PostgreSQL 支持的 Python 适配器)的文档,我们会发现它会引发 psycopg2.extensions.TransactionRollbackError:

exception psycopg2.extensions.TransactionRollbackError (subclasses OperationalError)

Error causing transaction rollback (deadlocks, serialization failures, etc).

但是 Django 用它做什么呢?好吧,作为 documented here,它将标准 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 确实是处理事务问题的正确异常类型,因此捕获它有望成为一个相当有效的数据库-不可知的解决方案。