#20571: Using savepoints within transaction.atomic() can result in the entire
transaction being incorrectly and silently rolled back
-------------------------------------+-------------------------------------
     Reporter:  lamby                |                    Owner:  nobody
         Type:                       |                   Status:  new
  Cleanup/optimization               |                  Version:
    Component:  Documentation        |  1.6-alpha-1
     Severity:  Release blocker      |               Resolution:
     Keywords:                       |             Triage Stage:  Accepted
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by lamby):

 Replying to [comment:2 aaugustin]:
 > Technically, the inner block in the example above is strictly equivalent
 to:
 >
 > {{{
 > with transaction.atomic():
 >     User.objects.create(pk=user.pk)
 > }}}

 Yes, although one still needs to catch the DatabaseError to be literally
 identical. :)

 > I'm in favor of the second solution because I still have to see a use
 case that isn't covered by `transaction.atomic()`. There aren't many
 patterns for using savepoints in an application.

 Just for clarity: I assume here you mean there aren't many patterns for
 using savepoints *that are not also covered by using transaction.atomic*.

 > I wonder if savepoint_commit() and savepoint_rollback() could just mark
 the transaction block as "correct" again. Wouldn't this solve the problem?

 No. That's too blunt as there is no way to know we are rolling back to a
 savepoint that results in a clean block. I'm not explaining that very
 well, so here's an untested example:

 {{{
 with transaction.atomic():
     s1 = transaction.savepoint()
     try:
         User.objects.create(pk=user.pk)
     except DatabaseError:
         # block now correctly marked as requiring rollback

         s2 = transaction.savepoint()
         # [..]
         transaction.savepoint_rollback(s2)

         # Oops. Assuming your solution, the block would now be incorrectly
         # marked as *not* requiring rollback even though it is required
         # due to the User.objects.create failure. We would only be able to
         # mark the block as clean if we rolled back to s1, but we have no
         # way of knowing that.
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/20571#comment:4>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" 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].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/063.b2bfbe69ed6065ed92bdd79be672b33e%40djangoproject.com?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to