On Mon, Oct 15, 2012 at 9:43 AM, Tom Evans <tevans...@googlemail.com> wrote:

> On Mon, Oct 15, 2012 at 1:50 PM, Zheng Li <dllizh...@gmail.com> wrote:
> > get_or_create shouldn't give duplicate entry error
> > anyone help.
> >
>
> This is incorrect, and a common misconception: get_or_create() is not
> atomic. If this happens, you will get duplicate key errors:
>

No, get_or_create IS intended to be atomic.


>
> Thread A calls get_or_create(a='a', b='b')
> Thread B calls get_or_create(a='a', b='b')
> Thread A get_or_create looks for entry in DB, not found
> Thread B get_or_create looks for entry in DB, not found
> Thread B creates entry in DB
> Thread A get_or_create tries to create entry in DB
>

Internally, get_or_create code in thread A will now attempt to GET the
object created by thread B. It will not automatically reflect the error to
the caller. See:

https://github.com/django/django/blob/stable/1.4.x/django/db/models/query.py#L430


>
> Where I say 'thread', you could also read 'process'. If you are
> capable of serving multiple requests simultaneously, this can happen,
> even if you aren't using threads.
>
> If this is a problem for you, use a transaction aware DB instead of
> MySQL. It won't solve the issue, but at least you will be able to
> unroll the transaction.
>

The issue with MySQL here is when you ARE using its transactional DB
engine, InnoDB, AND using its (default) "repeatable read" transaction
isolation level. In that case, the DB will refuse to return the object
created by thread B to thread A if thread A has already "read" the
non-existence of such a row. See:

https://code.djangoproject.com/ticket/13906

This particular issue can be fixed by changing the transaction isolation
level to "read committed". Although I have heard various people say this
can cause "other problems" with MySQL apps, I've never seen a concrete
example of one, so switching to "read committed" would be my preferred way
to use get_or_created if I had to use MySQL/InnoDB.

Karen
-- 
http://tracey.org/kmt/

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com.
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en.

Reply via email to