2008-08-24 06:25:40 +08:00
|
|
|
.. _topics-db-transactions:
|
|
|
|
|
2006-05-02 09:31:56 +08:00
|
|
|
==============================
|
|
|
|
Managing database transactions
|
|
|
|
==============================
|
|
|
|
|
2006-07-24 10:39:50 +08:00
|
|
|
Django gives you a few ways to control how database transactions are managed,
|
|
|
|
if you're using a database that supports transactions.
|
2006-05-02 09:31:56 +08:00
|
|
|
|
|
|
|
Django's default transaction behavior
|
|
|
|
=====================================
|
|
|
|
|
2009-05-02 15:40:25 +08:00
|
|
|
Django's default behavior is to run with an open transaction which it
|
|
|
|
commits automatically when any built-in, data-altering model function is
|
|
|
|
called. For example, if you call ``model.save()`` or ``model.delete()``, the
|
|
|
|
change will be committed immediately.
|
2006-05-02 09:31:56 +08:00
|
|
|
|
|
|
|
This is much like the auto-commit setting for most databases. As soon as you
|
|
|
|
perform an action that needs to write to the database, Django produces the
|
|
|
|
``INSERT``/``UPDATE``/``DELETE`` statements and then does the ``COMMIT``.
|
|
|
|
There's no implicit ``ROLLBACK``.
|
|
|
|
|
|
|
|
Tying transactions to HTTP requests
|
|
|
|
===================================
|
|
|
|
|
|
|
|
The recommended way to handle transactions in Web requests is to tie them to
|
|
|
|
the request and response phases via Django's ``TransactionMiddleware``.
|
|
|
|
|
|
|
|
It works like this: When a request starts, Django starts a transaction. If the
|
|
|
|
response is produced without problems, Django commits any pending transactions.
|
|
|
|
If the view function produces an exception, Django rolls back any pending
|
|
|
|
transactions.
|
|
|
|
|
|
|
|
To activate this feature, just add the ``TransactionMiddleware`` middleware to
|
|
|
|
your ``MIDDLEWARE_CLASSES`` setting::
|
|
|
|
|
|
|
|
MIDDLEWARE_CLASSES = (
|
2006-05-26 12:05:02 +08:00
|
|
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
|
|
|
'django.middleware.common.CommonMiddleware',
|
|
|
|
'django.middleware.cache.CacheMiddleware',
|
|
|
|
'django.middleware.transaction.TransactionMiddleware',
|
2006-05-02 09:31:56 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
The order is quite important. The transaction middleware applies not only to
|
|
|
|
view functions, but also for all middleware modules that come after it. So if
|
|
|
|
you use the session middleware after the transaction middleware, session
|
|
|
|
creation will be part of the transaction.
|
|
|
|
|
|
|
|
An exception is ``CacheMiddleware``, which is never affected. The cache
|
|
|
|
middleware uses its own database cursor (which is mapped to its own database
|
|
|
|
connection internally).
|
|
|
|
|
|
|
|
Controlling transaction management in views
|
|
|
|
===========================================
|
|
|
|
|
|
|
|
For most people, implicit request-based transactions work wonderfully. However,
|
|
|
|
if you need more fine-grained control over how transactions are managed, you
|
|
|
|
can use Python decorators to change the way transactions are handled by a
|
|
|
|
particular view function.
|
|
|
|
|
|
|
|
.. note::
|
|
|
|
|
|
|
|
Although the examples below use view functions as examples, these
|
|
|
|
decorators can be applied to non-view functions as well.
|
|
|
|
|
2009-03-11 15:06:50 +08:00
|
|
|
.. _topics-db-transactions-autocommit:
|
|
|
|
|
2006-05-02 09:31:56 +08:00
|
|
|
``django.db.transaction.autocommit``
|
|
|
|
------------------------------------
|
|
|
|
|
|
|
|
Use the ``autocommit`` decorator to switch a view function to Django's default
|
|
|
|
commit behavior, regardless of the global transaction setting.
|
|
|
|
|
|
|
|
Example::
|
|
|
|
|
|
|
|
from django.db import transaction
|
|
|
|
|
|
|
|
@transaction.autocommit
|
|
|
|
def viewfunc(request):
|
|
|
|
....
|
|
|
|
|
|
|
|
Within ``viewfunc()``, transactions will be committed as soon as you call
|
|
|
|
``model.save()``, ``model.delete()``, or any other function that writes to the
|
|
|
|
database.
|
|
|
|
|
|
|
|
``django.db.transaction.commit_on_success``
|
|
|
|
-------------------------------------------
|
|
|
|
|
|
|
|
Use the ``commit_on_success`` decorator to use a single transaction for
|
|
|
|
all the work done in a function::
|
|
|
|
|
|
|
|
from django.db import transaction
|
|
|
|
|
|
|
|
@transaction.commit_on_success
|
|
|
|
def viewfunc(request):
|
|
|
|
....
|
|
|
|
|
|
|
|
If the function returns successfully, then Django will commit all work done
|
|
|
|
within the function at that point. If the function raises an exception, though,
|
|
|
|
Django will roll back the transaction.
|
|
|
|
|
|
|
|
``django.db.transaction.commit_manually``
|
|
|
|
-----------------------------------------
|
|
|
|
|
|
|
|
Use the ``commit_manually`` decorator if you need full control over
|
|
|
|
transactions. It tells Django you'll be managing the transaction on your own.
|
|
|
|
|
|
|
|
If your view changes data and doesn't ``commit()`` or ``rollback()``, Django
|
|
|
|
will raise a ``TransactionManagementError`` exception.
|
|
|
|
|
|
|
|
Manual transaction management looks like this::
|
|
|
|
|
|
|
|
from django.db import transaction
|
|
|
|
|
|
|
|
@transaction.commit_manually
|
|
|
|
def viewfunc(request):
|
|
|
|
...
|
|
|
|
# You can commit/rollback however and whenever you want
|
|
|
|
transaction.commit()
|
|
|
|
...
|
|
|
|
|
|
|
|
# But you've got to remember to do it yourself!
|
|
|
|
try:
|
|
|
|
...
|
|
|
|
except:
|
|
|
|
transaction.rollback()
|
|
|
|
else:
|
|
|
|
transaction.commit()
|
|
|
|
|
2006-05-15 19:33:17 +08:00
|
|
|
.. admonition:: An important note to users of earlier Django releases:
|
2006-05-02 09:31:56 +08:00
|
|
|
|
|
|
|
The database ``connection.commit()`` and ``connection.rollback()`` methods
|
2008-08-15 21:44:43 +08:00
|
|
|
(called ``db.commit()`` and ``db.rollback()`` in 0.91 and earlier) no
|
|
|
|
longer exist. They've been replaced by ``transaction.commit()`` and
|
2006-05-02 09:31:56 +08:00
|
|
|
``transaction.rollback()``.
|
|
|
|
|
|
|
|
How to globally deactivate transaction management
|
|
|
|
=================================================
|
|
|
|
|
|
|
|
Control freaks can totally disable all transaction management by setting
|
|
|
|
``DISABLE_TRANSACTION_MANAGEMENT`` to ``True`` in the Django settings file.
|
|
|
|
|
|
|
|
If you do this, Django won't provide any automatic transaction management
|
|
|
|
whatsoever. Middleware will no longer implicitly commit transactions, and
|
|
|
|
you'll need to roll management yourself. This even requires you to commit
|
|
|
|
changes done by middleware somewhere else.
|
|
|
|
|
|
|
|
Thus, this is best used in situations where you want to run your own
|
|
|
|
transaction-controlling middleware or do something really strange. In almost
|
|
|
|
all situations, you'll be better off using the default behavior, or the
|
|
|
|
transaction middleware, and only modify selected functions as needed.
|
2006-07-24 10:39:50 +08:00
|
|
|
|
|
|
|
Transactions in MySQL
|
|
|
|
=====================
|
|
|
|
|
|
|
|
If you're using MySQL, your tables may or may not support transactions; it
|
|
|
|
depends on your MySQL version and the table types you're using. (By
|
|
|
|
"table types," we mean something like "InnoDB" or "MyISAM".) MySQL transaction
|
|
|
|
peculiarities are outside the scope of this article, but the MySQL site has
|
|
|
|
`information on MySQL transactions`_.
|
|
|
|
|
|
|
|
If your MySQL setup does *not* support transactions, then Django will function
|
|
|
|
in auto-commit mode: Statements will be executed and committed as soon as
|
|
|
|
they're called. If your MySQL setup *does* support transactions, Django will
|
|
|
|
handle transactions as explained in this document.
|
|
|
|
|
2008-08-15 21:44:43 +08:00
|
|
|
.. _information on MySQL transactions: http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-transactions.html
|
2009-05-02 15:40:25 +08:00
|
|
|
|
|
|
|
Transactions and savepoints in PostgreSQL 8
|
|
|
|
===========================================
|
|
|
|
|
|
|
|
When a call to a PostgreSQL 8 cursor raises an exception, all subsequent SQL
|
|
|
|
in the same transaction fails with the error "current transaction is aborted,
|
|
|
|
queries ignored until end of transaction block". Whilst simple use of save()
|
|
|
|
is unlikely to raise an exception in PostgreSQL, there are many more advanced
|
|
|
|
usage patterns which might: for example, saving objects with unique fields,
|
|
|
|
saving using the force_insert/force_update flag, or invoking custom SQL.
|
|
|
|
|
|
|
|
In any of these cases, you can wrap the command which may throw
|
|
|
|
IntegrityError inside savepoints, which will then allow subsequent commands
|
|
|
|
to proceed. Example::
|
|
|
|
|
|
|
|
try:
|
|
|
|
sid = transaction.savepoint()
|
|
|
|
x.save()
|
|
|
|
transaction.savepoint_commit(sid)
|
|
|
|
except IntegrityError:
|
|
|
|
transaction.savepoint_rollback(sid)
|
|
|
|
raise
|
|
|
|
|
|
|
|
Savepoints are not implemented in PostgreSQL 7. If you experience an
|
|
|
|
IntegrityError when using PostgreSQL 7, you will need to rollback to the
|
|
|
|
start of the transaction.
|