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.