繁体   English   中英

如何在循环 django 中回滚事务

[英]How to rollback transactions in a loop django

如果循环中抛出异常,我将尝试回滚一组事务。 但我不想跳出循环或抛出异常而不捕获它。

如果循环中的任何子项抛出异常,我不希望保存业务逻辑。 所以这意味着我不能将事务放入循环中,因为如果它们中的任何一个失败,它只会回滚特定子级的事务。

parent = Parent.objects.get(pk='something')
exceptions = []
with transaction.atomic():
    for child in parent.children.all():
        try:
            # business logic which also saves other models
            # I don't want this saved if there is an exception for any object in the loop
        except Exception as e:
            exceptions.append({
                'id': child.id,
                'error': str(e),
            })
if len(exceptions) > 0:
    transaction.set_rollback(True)
    for exception in exceptions:
        Child.objects.filter(pk=exception['id']) \
            .update(error=exception['error']
    # more business logic and raise exception
    parent.is_blocked = True
    parent.save()
    # I don't want this exception to rollback all transactions
    raise Exception('Parent {} is blocked'.format(parent.id))

上面的代码出现错误。 该消息非常直接。 我正在尝试回滚块外的事务。

django.db.transaction.TransactionManagementError: The rollback flag doesn't work outside of an 'atomic' block.

有没有人找到一种方法来处理这样的事情。 我希望我只是错过了一些简单的东西。 如果您需要更多信息,请告诉我。

Avoid catching exceptions inside atomic!

按照文档,在你的特殊情况下,你的代码应该是这样的:

parent = Parent.objects.get(pk='something')
exceptions = []
try:
    with transaction.atomic():
        for child in parent.children.all():
            try:
                # business logic which also saves other models
                # I don't want this saved if there is an exception for any object in the loop
            except Exception as e:
                exceptions.append({
                    'id': child.id,
                    'error': str(e),
                })
        # raise exception handly to trigger rollback
        if len(exceptions) > 0:
            raise("raise for rollback")
except Exception as e:
    pass

if len(exceptions) > 0:
    for exception in exceptions:
        Child.objects.filter(pk=exception['id']) \
            .update(error=exception['error']
    # more business logic and raise exception
    parent.is_blocked = True
    parent.save()
    # I don't want this exception to rollback all transactions
    raise Exception('Parent {} is blocked'.format(parent.id))

您可以尝试生成器函数:

def function():
    for child in parent.children.all():
        try:
            yield result
        except Exception as e:
            yield exception

为清楚起见,您可以查看此答案: 如何处理生成器函数中抛出的错误

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM