If the `innocent_looking_function` would use transactions. And thus handles
the `IntegrityError by`
issuing a rollback, just like `get_or_create` does (
https://github.com/django/django/blob/1.6b4/django/db/models/query.py#L360-L390
).
Do you see the same behaviour in `my_func`?

-- Gert

Mobile: +32 498725202
Twitter: @gvangool <http://twitter.com/gvangool>
Web: http://gertvangool.be


On Thu, Sep 19, 2013 at 2:38 PM, Richard Ward <[email protected]>wrote:

> 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.
>

-- 
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