Hi Carsten,

> Why will the other thread block?
> (Both threads may enter the "create" case, so the select_for_update() may 
not
> yet be effective for the other thread?)

> I looked into get_or_create()'s source code and the 
_create_object_from_params()
> method that it calls. Is this due to the "second"
>         return self.get(**lookup), False
> near its end? 

Exactly. Only one thread will succeed in creating the object. The other one 
will
get an `IntegrityError` and try to `.get()` the existing object which is 
going
to use `select_for_update(nowait=False)`-- a blocking call.

> Also, I understand the purpose of wrapping demonstrate_the_problem() in
> atomic(), accounting for possibly unrelated exceptions in "long 
`some_value`
> computation". But why does _create_object_from_params() wrap its single 
call to
> `create()` in atomic(), too? Isn't create() inherently atomic? 

The create() method is atomic but in order to recover from an integrity 
error
it could raise on conflictual data it must be wraped in a transaction
(if autocommit is on) or use a savepoint in your case because a transaction
is already started by the demonstrate_the_problem() atomic wrapper. Else the
connection is left in an unusable state by the integrity error.

Cheers,
Simon

Le jeudi 12 mai 2016 10:48:30 UTC-4, Carsten Fuchs a écrit :
>
> Hi Simon, 
>
> many thanks for your reply! 
> Please see below for some follow-up questions. 
>
> Am 11.05.2016 um 16:04 schrieb Simon Charette: 
> > Did you try using select_for_update() with get_or_create()[1] in an 
> > atomic()[2] context? 
> > 
> > @transation.atomic 
> > def demonstrate_the_problem(): 
> >      d = date.today() 
> >      t = TestModel.objects.select_for_update().get_or_create( 
> >          jahr=d.year, monat=d.month 
> >      ) 
> >      # ... long `some_value` computation 
> >      t.some_value = 123 
> >      t.save(update_fields={'some_value'}) 
> >      return t 
> > 
> > Note that in this case if another thread tries to select_for_update() it 
> is 
> > going to block at the get_of_create() until the first thread's 
> transaction 
> > commits. 
>
> Why will the other thread block? 
> (Both threads may enter the "create" case, so the select_for_update() may 
> not 
> yet be effective for the other thread?) 
>
> I looked into get_or_create()'s source code and the 
> _create_object_from_params() 
> method that it calls. Is this due to the "second" 
>         return self.get(**lookup), False 
> near its end? 
>
> Also, I understand the purpose of wrapping demonstrate_the_problem() in 
> atomic(), accounting for possibly unrelated exceptions in "long 
> `some_value` 
> computation". But why does _create_object_from_params() wrap its single 
> call to 
> `create()` in atomic(), too? Isn't create() inherently atomic? 
>
> Best regards, 
> Carsten 
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" 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 https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/caaa0bd5-f2dc-4987-ace0-e94cb68599c6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to