使用 django select_for_update 不回滚错误
Using django select_for_update without rolling back on error
我正在尝试通过 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
来管理事务来推出我自己的解决方案,但我认为会有更简单的方法来获得此功能。有没有内置的方法来实现我想要的?
我最终选择了如下所示的内容:
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
块中,反之亦然。
我正在尝试通过 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
来管理事务来推出我自己的解决方案,但我认为会有更简单的方法来获得此功能。有没有内置的方法来实现我想要的?
我最终选择了如下所示的内容:
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
块中,反之亦然。