Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django 1.6 and nesting "with transaction.atomic()"

I've got used through the years to the older transaction.commit_on_success and transaction.commit_manually with Django < 1.6. But now with Django 1.6 the old API is replaced mainly with transaction.atomic.

After reading the docs on the new API, I'm still not sure how the following code will be committed to the database:

def a_first_function():
    with transaction.atomic():
        a_second_function_successful()
        a_third_function_fails()

def a_second_function_successful():
    with transaction.atomic():
        do_something()

def a_third_function_fails():
    do_something_wrong()

In this example, let's assume that a_second_function_successful called from a_first_function succeeds and creates/saves objects from models. Immediately after this second_function succeeds, the third function is called and fails.

Given that transaction.atomic using the context manager is both used in the first and second function, what will happen to the data created/modified in a_second_function_successful. Will it be committed to the database? Will it be rolled back automatically from the first function? My experience is that it the second function will be committed regardless, however, I expected it not to be committed.

Would it make any difference now if the third function was defined as the following:

@transaction.atomic
def a_third_function_fails():
    do_something_wrong()

or as:

def a_third_function_fails():
    with transaction.atomic():
        do_something_wrong()

Thanks,

like image 502
Loic Duros Avatar asked Dec 02 '13 21:12

Loic Duros


1 Answers

Well I would say if you don't have any try except blocks to catch the exceptions triggering the rollback than everything will be rolled back, as the exception will propagate to the topmost with transaction.atomic() from a_first_function(), even if it is raised from a_third_function_fails()

However if you were to catch the exception in a_third_function_fails which means you would also have to do something like:

def a_third_function_fails():
    try:
        with transaction.atomic():
            do_something_wrong()
    except:
        pass

Then you would have the third function roll back and not the second function because you are implicitly creating a savepoint when you call with transaction.atomic() from a_third_function_fails.

like image 60
j1z0 Avatar answered Sep 20 '22 01:09

j1z0