Hello there,

I have recently updated to django 1.7, from 1.5 and one of the main changes 
I had to do was to replace all deprecated transaction.commit_manually to 
transaction.atomic, so far so good.

After this, I have found out that if an IntegrityError or DatabaseError 
exception happen inside a code that is decorated with @transaction.atomic 
(or inside a with transaction.atomic) and the exception is handled (not 
throwing it out from the atomic block) the whole transaction gets invalid, 
and any other database access will fail, just as described in the docs 
(silly me I didn't read them with enough depth).

As mentioned in the docs, the solution is to also put the "exception 
throwing code" inside another atomic block, and catch the exception outside 
of it. I can not describe how anoying this is, compared to the old 
behaviour where I could easly decide when to commit or rollback, now I have 
to review my whole code to detect the places where a database save is 
performed and the exception is handled, and add another atomic block to it.

I believe this was an issue heavily discussed with the develpers and they 
came to this as the best option, but there needs to be another easier way 
to handle this kind of issue.
What are the complications of leaving the transaction in a correct state 
even if an operation raises a database error and the exception is handled 
silently (not thrown outside of the atomic block)? This was totally 
possible with the deprecated transaction functions, where you could do all 
your logic and just at the end handle the transaction commit or rollback, 
and didn't matter what happened inside of it. But now this is imposible, 
you need to keep a sharp eye on every database save you perform and 
surround it with another atomic block just in case it raises a database 
error exception.


To make the issue clear, here's a sample code:

First one shows what would my current code look like, where add_children() 
would raise an exception because generate_relationships() was not inside 
another atomic block.
With the old transactions api, I could easily surround the whole code in 
another try/except, and at the very end commit or rollback, and everything 
would be fine even if generate_relationships() throws an exception, it 
would be siltently ignored.

from django.db import IntegrityError, transaction
@transaction.atomicdef viewfunc(request):
    create_parent()

    try:        
        generate_relationships()
    except IntegrityError:
        handle_exception()

    add_children()



Now this is how the code should actually be with current django 1.7 in 
order to prevent an error and get the excepted behaviour.

from django.db import IntegrityError, transaction
@transaction.atomicdef viewfunc(request):
    create_parent()

    try:
        with transaction.atomic():
            generate_relationships()
    except IntegrityError:
        handle_exception()

    add_children()


It would be great, if the transaction api could work as the first code, 
with the results of the second one. Meaning, even if 
generate_relationships() raises an exception, and it is handled correctly, 
the transaction would still be valid to be used.

Thanks!

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/e347fe6d-78c8-4c15-848d-3a82415c3550%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to