We're building a site that needs to use transactions, and have been doing 
so against the 1.6 beta as 1.6 is nearly out and we thought it would be 
easier to use the new transaction api, but we came across an unexpected 
problem. 

Basically if you catch an IntegrityError and 'recover' from it, then your 
transaction is still not committed.

I'm posting this here rather than in django-users as its a feature in an 
unreleased version and it seems like it a bug to me (apologies if it is the 
wrong place).

Take this code:

def innocent_looking_function():
    "Makes sure that a MyModel with foo=1 exists"
    try: 
        #imagine mymodel has a unique constraint on 'foo'
        MyModel(foo=1).save() 
    except IntegrityError: 
        pass

@transaction.atomic 
def my_func(): 
    innocent_looking_function() 
    MyOtherModel(bar="hi").save() 

If you call 'my_func' when a MyModel with foo=1 exists, then the 
transaction.atomic decorator will roll back the transaction, even though it 
seems like everything is alright. 'my_func' doesn't know that 
'innocent_looking_func' may cause this behaviour, and as far as 
'innocent_looking_func' is concerned it has not done anything wrong - it 
caught and ignored a harmless error.

I had assumed that transaction.atomic would only roll back the transaction 
if an exception was propagated through it (eg if innocent_looking_function 
did not catch the error), that would seem like the natural way of doing 
things.

So what is the problem here? I assume it is one of:

   1. 'innocent_looking_function' is badly written: it should not be 
   catching IntegrityErrors under any circumstances (though that seems like a 
   valid thing to do), it should instead use something like get_or_create.
   2. 'innocent_looking_function' should have 'with transaction.atomic():' 
   just inside the 'try' block, and presumably so should every other bit of 
   code where an IntegrityError is caught. But what if 
   'innocent_looking_function' also gets used elsewhere that may not be inside 
   an atomic block?
   3. transaction.atomic is in some way buggy / oddly designed.

IMO this behaviour makes code that looks valid (to me) not work in the 
expected way.

In case its relevant I'm using InnoDB tables on MySQL.

So Is there a bug? Or am I using this incorrectly, or misunderstanding 
something?

Thanks,

Richard

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-developers.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to