1

select_for_update我正在尝试通过使用该实用程序来利用 django 的行级锁定。根据文档,这只能在transaction.atomic块内使用。使用块的副作用transaction.atomic是,如果我的代码抛出异常,所有数据库更改都会回滚。我的用例是这样的,我实际上希望保留数据库更改,并允许传播异常。这让我的代码看起来像这样:

with transaction.atomic():
    user = User.objects.select_for_update.get(id=1234)
    try:
        user.do_something()
    except Exception as e:
        exception = e
    else:
        exception = None

if exception is not None:
    raise exception

这感觉像是一个完全的反模式,我敢肯定我一定遗漏了一些东西。我知道我可能会通过手动使用transaction.set_autocommit来管理事务来推出我自己的解决方案,但我认为会有一种更简单的方法来获得这个功能。有没有一种内置的方式来实现我想要的?

4

1 回答 1

1

我最终选择了如下所示的东西:

from django.db import transaction

class ErrorTolerantTransaction(transaction.Atomic):

    def __exit__(self, exc_type, exc_value, traceback):
        return super().__exit__(None, None, None)


def error_tolerant_transaction(using=None, savepoint=True):
    """
    Wraps a code block in an 'error tolerant' transaction block to allow the use of
    select_for_update but without the effect of automatic rollback on exception.

    Can be invoked as either a decorator or context manager.
    """
    if callable(using):
        return ErrorTolerantTransaction('default', savepoint)(using)

    return ErrorTolerantTransaction(using, savepoint)

我现在可以error_tolerant_transaction代替,transaction.atomic并且可以在不强制回滚的情况下引发异常。当然,与数据库相关的异常(即 IntegrityError)仍然会导致回滚,但鉴于我们正在使用事务,这是预期的行为。作为奖励,此解决方案与 兼容transaction.atomic,这意味着它可以嵌套在atomic块内,反之亦然。

于 2017-08-15T12:04:33.180 回答