Opened 10 years ago
Closed 10 years ago
#24009 closed Uncategorized (needsinfo)
get_or_create can raise an IntegrityError in race conditions
Reported by: | Mihail Milushev | Owned by: | nobody |
---|---|---|---|
Component: | Uncategorized | Version: | 1.7 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
get_or_create
is described as being atomic in the documentation, but that is not the case. Since it first tries to retrieve an existing record and if that fails it tries to create a new one, another thread can create that record in the small interval between the two operations. This will not result in data corruption as the database will enforce its constraints, but it makes the whole convenience method not that convenient, if I also need to handle this in a try
block around its invocation. If I _need_ to do try: get_or_create() except IntegrityError: get()
anyway, it makes no sense to use get_or_create
in the first place, that logic would work if I just try to create the entity and only retrieve it if the create raises an IntegrityError
.
When I call get_or_create
I expect it to return the existing record, or to create a new record if one does not exist yet. Getting an IntegrityError
there is like saying "there's no existing record, but I cannot create a new one because one already exists".
Change History (4)
comment:1 by , 10 years ago
comment:2 by , 10 years ago
No, I'm using PostgreSQL, and wrapping each get_or_create
in an individual transaction context will again make get_or_create
worthless by requiring at least as much boilerplate around it as it would take to implement the get-or-create logic myself without using get_or_create
.
comment:3 by , 10 years ago
As far as I can tell, the IntegrityError
you describe should be caught by Django. Did you run into this problem with Django 1.7?
comment:4 by , 10 years ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
This may be a duplicate of #13906. Are you using MySQL with
REPEATABLE READ
?