Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.0.X] Fixed #9206 -- Added documentation on savepoints, and how to …

…use them to recover from errors in PostgreSQL. Thanks to Richard Davies for the draft text.

Merge of r10791 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.0.X@10792 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit f5dcd07977a00ef84fc24ba5719ea86a453b1c8c 1 parent 985c939
Russell Keith-Magee authored May 16, 2009

Showing 1 changed file with 105 additions and 19 deletions. Show diff stats Hide diff stats

  1. 124  docs/topics/db/transactions.txt
124  docs/topics/db/transactions.txt
@@ -148,6 +148,67 @@ transaction-controlling middleware or do something really strange. In almost
148 148
 all situations, you'll be better off using the default behavior, or the
149 149
 transaction middleware, and only modify selected functions as needed.
150 150
 
  151
+.. _topics-db-transactions-savepoints:
  152
+
  153
+Savepoints
  154
+==========
  155
+
  156
+A savepoint is a marker within a transaction that enables you to roll back
  157
+part of a transaction, rather than the full transaction. Savepoints are
  158
+available to the PostgreSQL 8 and Oracle backends. Other backends will
  159
+provide the savepoint functions, but they are empty operations - they won't
  160
+actually do anything.
  161
+
  162
+Savepoints aren't especially useful if you are using the default
  163
+``autocommit`` behaviour of Django. However, if you are using
  164
+``commit_on_success`` or ``commit_manually``, each open transaction will build
  165
+up a series of database operations, awaiting a commit or rollback. If you
  166
+issue a rollback, the entire transaction is rolled back. Savepoints provide
  167
+the ability to perform a fine-grained rollback, rather than the full rollback
  168
+that would be performed by ``transaction.rollback()``.
  169
+
  170
+Savepoints are controlled by three methods on the transaction object:
  171
+
  172
+.. method:: transaction.savepoint()
  173
+
  174
+    Creates a new savepoint. This marks a point in the transaction that
  175
+    is known to be in a "good" state.
  176
+
  177
+    Returns the savepoint ID (sid).
  178
+
  179
+.. method:: transaction.savepoint_commit(sid)
  180
+
  181
+    Updates the savepoint to include any operations that have been performed
  182
+    since the savepoint was created, or since the last commit.
  183
+
  184
+.. method:: transaction.savepoint_rollback(sid)
  185
+
  186
+    Rolls the transaction back to the last point at which the savepoint was
  187
+    committed.
  188
+
  189
+The following example demonstrates the use of savepoints::
  190
+
  191
+    from django.db import transaction
  192
+
  193
+    @transaction.commit_manually
  194
+    def viewfunc(request):
  195
+
  196
+      a.save()
  197
+      # open transaction now contains a.save()
  198
+      sid = transaction.savepoint()
  199
+
  200
+      b.save()
  201
+      # open transaction now contains a.save() and b.save()
  202
+
  203
+      if want_to_keep_b:
  204
+          transaction.savepoint_commit(sid)
  205
+          # open transaction still contains a.save() and b.save()
  206
+      else:
  207
+          transaction.savepoint_rollback(sid)
  208
+          # open transaction now contains only a.save()
  209
+
  210
+      transaction.commit()
  211
+
151 212
 Transactions in MySQL
152 213
 =====================
153 214
 
@@ -164,28 +225,53 @@ handle transactions as explained in this document.
164 225
 
165 226
 .. _information on MySQL transactions: http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-transactions.html
166 227
 
167  
-Transactions and savepoints in PostgreSQL 8
168  
-===========================================
  228
+Handling exceptions within PostgreSQL transactions
  229
+==================================================
  230
+
  231
+When a call to a PostgreSQL cursor raises an exception (typically
  232
+``IntegrityError``), all subsequent SQL in the same transaction will fail with
  233
+the error "current transaction is aborted, queries ignored until end of
  234
+transaction block". Whilst simple use of ``save()`` is unlikely to raise an
  235
+exception in PostgreSQL, there are more advanced usage patterns which
  236
+might, such as saving objects with unique fields, saving using the
  237
+force_insert/force_update flag, or invoking custom SQL.
169 238
 
170  
-When a call to a PostgreSQL 8 cursor raises an exception, all subsequent SQL
171  
-in the same transaction fails with the error "current transaction is aborted,
172  
-queries ignored until end of transaction block". Whilst simple use of save()
173  
-is unlikely to raise an exception in PostgreSQL, there are many more advanced
174  
-usage patterns which might: for example, saving objects with unique fields,
175  
-saving using the force_insert/force_update flag, or invoking custom SQL.
  239
+There are several ways to recover from this sort of error.
176 240
 
177  
-In any of these cases, you can wrap the command which may throw
178  
-IntegrityError inside savepoints, which will then allow subsequent commands
179  
-to proceed. Example::
  241
+Transaction rollback
  242
+--------------------
180 243
 
  244
+The first option is to roll back the entire transaction. For example::
  245
+
  246
+    a.save() # Succeeds, but may be undone by transaction rollback
181 247
     try:
182  
-      sid = transaction.savepoint()
183  
-      x.save()
184  
-      transaction.savepoint_commit(sid)
  248
+        b.save() # Could throw exception
  249
+    except IntegrityError:
  250
+        transaction.rollback()
  251
+    c.save() # Succeeds, but a.save() may have been undone
  252
+
  253
+Calling ``transaction.rollback()`` rolls back the entire transaction. Any
  254
+uncommitted database operations will be lost. In this example, the changes
  255
+made by ``a.save()`` would be lost, even though that operation raised no error
  256
+itself.
  257
+
  258
+Savepoint rollback
  259
+------------------
  260
+
  261
+If you are using PostgreSQL 8 or later, you can use :ref:`savepoints
  262
+<topics-db-transactions-savepoints>` to control the extent of a rollback.
  263
+Before performing a database operation that could fail, you can set or update
  264
+the savepoint; that way, if the operation fails, you can roll back the single
  265
+offending operation, rather than the entire transaction. For example::
  266
+
  267
+    a.save() # Succeeds, and never undone by savepoint rollback
  268
+    try:
  269
+        sid = transaction.savepoint()
  270
+        b.save() # Could throw exception
  271
+        transaction.savepoint_commit(sid)
185 272
     except IntegrityError:
186  
-      transaction.savepoint_rollback(sid)
187  
-      raise
  273
+        transaction.savepoint_rollback(sid)
  274
+    c.save() # Succeeds, and a.save() is never undone
188 275
 
189  
-Savepoints are not implemented in PostgreSQL 7. If you experience an
190  
-IntegrityError when using PostgreSQL 7, you will need to rollback to the
191  
-start of the transaction.
  276
+In this example, ``a.save()`` will not be undone in the case where
  277
+``b.save()`` raises an exception.

0 notes on commit f5dcd07

Please sign in to comment.
Something went wrong with that request. Please try again.