12

I was browsing django's source and looked at get_or_create. Shouldn't it be wrapped with a transaction?

Thanks

reshefm
  • 6,017
  • 8
  • 36
  • 40
  • Question of the decade! I wonder why the decision to not make get_or_create atomic as well. Occasionally I see problems due to the non-atomic get_or_create. – Kekoa Feb 16 '11 at 16:13
  • Related: http://stackoverflow.com/questions/6416213/is-get-or-create-thread-safe – Stefano Feb 22 '12 at 18:14

1 Answers1

4

Looking at this diff it looks like as of Revision 8315, that has been handle explicitly within the get_or_create() method.

Update

As @reshefm pointed out, this was properly solved in rev 8670 where force_insert=True was added to obj.save() to ensure that during a race condition, all instances will attempt an insert (and not fall back to update) so only one will succeed while others will fail. Failing instances will proceed to do another get().

In terms of release version, this fix was first introduce in release 1.0.

Shawn Chin
  • 84,080
  • 19
  • 162
  • 191
  • Look again at the code of the same revision you posted. The get happens first(without transaction) and then a record is saved using a savepoint, but that still means you get a race condition because the get and create are not atomic together – Kekoa Feb 16 '11 at 18:05
  • Perhaps I'm missing something, but the code looks fine. Assuming two requests attempt a get and fails, both will proceed to do a create. Assuming `.save()` is atomic, one of them will succeed while the other fails. The failing one then continues to do a get to retrieve the recently added data. – Shawn Chin Feb 16 '11 at 21:17
  • Indeed I looked at the wrong revision. The line here: http://code.djangoproject.com/browser/django/trunk/django/db/models/query.py#L385 solves it. It forces an insert. – reshefm Feb 17 '11 at 09:33
  • @reshefm good point about `force_insert`. Will update answer for future reference. – Shawn Chin Feb 17 '11 at 09:54