[Django]-Django nested transactions – “with transaction.atomic()” — Seeking Clarification

63👍

✅

Here is some pseudo-code with nested transaction blocks and database operations X, Y, and Z:

with transaction.atomic():
    X
    with transaction.atomic():
        Y
    Z

If X raises an exception then obviously none of the operations will get the chance to commit in the first place.

If Y raises an exception—which was the question you referenced—then the outer block will also roll back. That doesn’t have anything to do with nested transactions, per se, it happens because the Python exception bubbles up. The outer block will be exited by an exception, which always causes a rollback. That’s true regardless of what caused the exception in the first place.

The non-obvious case is what happens when Z raises an exception, and that’s why the documentation calls it out for special attention. As referenced, both X and Y will be rolled back:

When an inner block completes successfully, its effects can still be rolled back if an exception is raised in the outer block at a later point.

Now, it’s also possible to catch the exception raised by the nested operation.

with transaction.atomic():
    X
    try:
        with transaction.atomic():
            Y
    except IntgrityError:
        pass
    Z

In this case, if Y throws an exception the inner block will be rolled back (because it exits with an exception) but the outer block won’t (because it doesn’t).

That doesn’t contradict the information in either of the two answers you mentioned since those addressed specific questions (with code examples) that didn’t involve catching any exceptions.

In any case, thanks for the feedback and the chance to give a more comprehensive answer.

1👍

Second example is catching IntegrityError so outer transaction atomic wont be aware of the following error occurring

Wrapping atomic in a try/except block allows for natural handling of
integrity errors

Which basically says if you want following block not to raise outer transaction rollback just try/catch integrity errors

As you already stated the following from documentation

atomic blocks can be nested. In this case, when an inner block
completes successfully, its effects can still be rolled back if an
exception is raised in the outer block at a later point.

So by default rollback will happen as error will propagate, and second example is a way to silence outer transaction rollback

Leave a comment