Django documentation

当前文档仅适用于 Django SVN 版本,与上个版本有显著不同。上个版本文档请查阅 Django 1.0

管理数据库事务(Managing database transactions)

如果你使用的数据库支持事务,那么 Django 提供了几种方法来管理数理库事务。

Django 默认的事务行为(Django’s default transaction behavior)

Django 默认情况下是运行一个打开的事务,这个事务在 model 中引起了数据变动的内置函式被调用时,就会被自动提交。例如,如果你调用 model.save()model.delete(),改动就会被自动提交。

这与很多数据库中的自动提交事务的设置相似。只要你执行了写数据库的动作,Django 就会生成对应的 INSERT/UPDATE/DELETE 语句,然后执行 COMMIT。这其中并没有暗含 ROLLBACK 回滚操作。

将 HTTP 请求与事务进行绑定(Tying transactions to HTTP requests)

这种方式适用于在 web 请求中处理事务的情况,通过 TransactionMiddleware 将 web 请求/ web 应答与事务进行绑定。

工作流程如此:当 Django 收到一个请求时,就会对某个事务进行处理。如果在生成应答的过程中没有出现问题,Django 就会提交未结束的事务。如果视图函式产生了异常,Django 就会回滚未结束的事务。

要激活这个特性,只要将 TransactionMiddleware 中间件添加到 MIDDLEWARE_CLASSES 设置即可:

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.cache.CacheMiddleware',
    'django.middleware.transaction.TransactionMiddleware',
)

这个顺序是相当重要的。事务中间件不仅仅只作用于视图函式,也对排在它后面的所有中间件起作用。如果你将 session 中间件放在事务中间件的后面,那么创建 session 也会变成事务的一部分。

CacheMiddleware 是一个例外,事务不会对它起作用。这是因为缓存中间件使用它自己的数据库游标(其内部使用自己的数据库游标)。

在视图中控制事务管理(Controlling transaction management in views)

对于大多数人来说,隐式的基于请求的事务工作得非常好。但是,如果你需要对如何管理事务做更细致的控制,那么你可以使用 Python 装饰器来改变这种由视图函式处理事务的方式。

注意

虽然下面的例子使用视图函式做为例子,但这些装饰器也可以作用于非视图函式。

django.db.transaction.autocommit

使用 autocommit 装饰器时,会忽略全局事务设置,将某个视图函式转换化 Django 默认的事务提交行为。

例如:

from django.db import transaction

@transaction.autocommit
def viewfunc(request):
    ....

viewfunc() 里,一旦你调用了 model.save()model.delete(),或是任何其他会写数据库的方法,事务就会被立刻提交。

django.db.transaction.commit_on_success

使用 commit_on_success 装饰器时,会令某个函式中每一项工作完成后都使用一个单独的事务:

from django.db import transaction

@transaction.commit_on_success
def viewfunc(request):
    ....

如果这个函式成功返回,接下来 Django 就会提交函式中所有已完成的工作。如果函式抛出异常,Django 就会对事务进行回滚。

django.db.transaction.commit_manually

如果需要对事务进行全面控制,可以使用 commit_manually 装饰器。它告诉 Django 你将全面接管这个事务。

如果你的视图修改了数据却没有 commit()rollback(), Django 将抛出 TransactionManagementError 异常。

手动管理事务如下:

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()

早期 Django 版本的用户请注意:

数据库 connection.commit()connection.rollback() 方法(在 Djanog 0.91 以及更早版本中被称为 db.commit()db.rollback() ) 已不在再在。它们已经被 transaction.commit()transaction.rollback() 替换。

如何使全局事务管理无效(How to globally deactivate transaction management)

在 Django 的配置文件中将 DISABLE_TRANSACTION_MANAGEMENT 设为 True 就会禁用所有的事务管理。

如果你如法设置,那么 Django 就不再自动提供任何的事务管理;中间件也不再隐式地提交事务,而且你需要自行去管理事务。甚至于你还要为其他的中间件提交事务。

因此,如果你想使用你自己写的事务中间件或是你想做一些非常古怪的东西,那么如上所做确实是最佳选择。但是在大多数情况下,你最好还是关闭默认的事务行为或去掉事务中间件,然后只修改必要的函式。

保存点(Savepoints)

保存点是事务内的一个标记,用来确保你能回滚部分事务,而不是回滚整个事务。保存点对 PostgreSQL 8Oracle 数据库是非常有用的。其他数据库也提供 savepoint 函式,但是却只是个空操作,不会执行任何操作。

如果你使用 Django 默认的autocommit 事务行为,那么保存点功能并不是特别有用。但是如果你使用 commit_on_successcommit_manually,每个打开的事务都积累了一系列数据库操作,等待提交或是回滚。如果你要求回滚,那么整个的事务都会被回滚。保存点提供了这样一种能力,它能操作回滚的细节,做部分回滚,而不是使用 transaction.rollback() 一次性全部回滚。

在事务对象中,保存点由三个方法控制:

transaction.savepoint()

创建一个新的保存点,它在事务标记一个点,表明当前是 "good" 状态。

返回保存点的 ID (sid).

transaction.savepoint_commit(sid)
更新保存点。它对自保存点被创建之后,事务中执行的所有操作进行保存;或是对上次提交之后的所有操作进行保存。
transaction.savepoint_rollback(sid)
将事务回滚到最后一次提交时的保存点。

下面这些例子演示了保存点的用法:

from django.db import transaction

@transaction.commit_manually
def viewfunc(request):

  a.save()
  # open transaction now contains a.save()
  sid = transaction.savepoint()

  b.save()
  # open transaction now contains a.save() and b.save()

  if want_to_keep_b:
      transaction.savepoint_commit(sid)
      # open transaction still contains a.save() and b.save()
  else:
      transaction.savepoint_rollback(sid)
      # open transaction now contains only a.save()

  transaction.commit()

MySQL 中的事务(Transactions in MySQL)

如果你正在使用 MySQL,那么你的表可能支持,也可能不支持事务;这取决于你的 MySQL 版本和表的类型(这里的表类型,就是指 "InnoDB" 或 "MyISAM")。 MySQL 的事务特性已经超出了本文所讨论的范围,如果您感兴趣,可以查看 information on MySQL transactions

如果你的 MySQL 不支持事务,那么 Django 将在 auto-commit 模式中实现这个功能:调用任何语句都被立刻被运行,然后提交。如果你的 MySQL 支持事务,Django 将使用上文中所提到的方法来处理事务。

在 PostgreSQL 事务中处理异常(Handling exceptions within PostgreSQL transactions)

在调用 PostgreSQL 标游时,如果抛出异常 (比如 IntegrityError),同个事务中的所有 SQL 子查询都会曗同样的错误 "当前事务被中断,查询将被忽视,直至事务结束 current transaction is aborted, queries ignored until end of transaction block"。只是简单地使用 save() 并不会在 PostgreSQL 中抛开异常,这通常出现在使用更先进的特性时,比如保存含有唯一字段的对象,或保存时使用了 force_insert/force_update 标识,或是使用自定义 SQL 。

下面几种方法可以避免这种错误。

事务回滚(Transaction rollback)

第一种方法就是回滚整个事务。例如:

a.save() # Succeeds, but may be undone by transaction rollback
try:
    b.save() # Could throw exception
except IntegrityError:
    transaction.rollback()
c.save() # Succeeds, but a.save() may have been undone

调用 transaction.rollback() 回滚整个事务。任何未提交的数据库操作都会丢失。在这个例子中, a.save() 所做的修改将丢失,而且不会抛出任何异常。

保存点回滚(Savepoint rollback)

如果你正在使用 PostgreSQL 8 或是更新版本,你可以使用 savepoints 来控制回滚范围。在执行一个可能会失败的数据库操作之前,你可以设置或是更新保存点。如果这个操作失败了,你可回滚到上一个提交的操作,而不是回滚整个事务。例如:

a.save() # Succeeds, and never undone by savepoint rollback
try:
    sid = transaction.savepoint()
    b.save() # Could throw exception
    transaction.savepoint_commit(sid)
except IntegrityError:
    transaction.savepoint_rollback(sid)
c.save() # Succeeds, and a.save() is never undone

在这个例子中,a.save() 将不会被回滚,而 b.save() 会抛出异常。

数据库级的自动提交(Database-level autocommit)

这部分是在 Django 1.1 中新增的: 请查看版本文档

在使用 PostgreSQL 8.2 或更新的版本时,可以使用 PostgreSQL 自带的一个先进特性 database-level autocommit。如果使用了这个特性,就不会出现打开而未提交的事务,所以即使使用了异常捕牛,它仍会继续运行。例如:

a.save() # succeeds
try:
    b.save() # Could throw exception
except IntegrityError:
    pass
c.save() # succeeds

注意

autocommit decorator 不同,在使用数据库级的自动提交时,是不存在数据库事务的。所以一个写数据库的操作发生时, autocommit 装饰器仍在使用事务,并自动提交每个事务。

Questions/Feedback

Having trouble? We'd like to help!