django官方文档——管理数据库事务
来源:互联网 发布:幸运转盘抽奖软件 编辑:程序博客网 时间:2024/04/20 19:29
管理数据库事务¶
如果你的数据库支持事务,那么 Django 提供了控制事务的多种方式。
Django 的缺省事务行为¶
缺省情况下, Django 运行的是开放性的事务,即当调用任何内建的改变数据的模型函数时事务会自动提交。例如,如果你 model.save() 或 model.delete() ,数据变动会自动立即提交。
这样很象大多数数据库设置的自动提交。一旦你执行了一个需要写数据库的动作,那么 Django 会执行 INSERT/UPDATE/DELETE 语句,然后提交,不会有隐式回滚 。
把事务与 HTTP 请求绑定¶
推荐的方式是通过 Django 的 TransactionMiddleware 来进行绑定。
其工作原理就象这样:当一个请求开始时, Django 就开始一个事务。如果顺利产生一个响应, Django 就提交这个阶段的事务。如果视图函数产生异常,就回滚。
要使用这个功能,只要把 TransactionMiddleware 中间件加入到MIDDLEWARE_CLASSES 设置中:
MIDDLEWARE_CLASSES = ( 'django.middleware.cache.UpdateCacheMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.transaction.TransactionMiddleware', 'django.middleware.cache.FetchFromCacheMiddleware',)
这些中间件的顺序是非常重要的。事务中间件不仅作用于视图函数,还作用于其后面的所有中间件模块。所以如果你把会话中间件放在事务中间件之后,那么会话创建也会变成事务的一部分。
但这几种中间件例外: CacheMiddleware 、UpdateCacheMiddleware 和FetchFromCacheMiddleware 。即使使用了数据库缓存, Django 的缓存后端还是使用其自己的数据库指针(指针内部映射到其自己的数据库连接)。
在视图中控制事务管理¶
对于大多数人来说,隐匿的基于请求的事务相当好用。但是如果要细粒度地控制事务管理,那么可以使用 django.db.transaction 中的一套函数来达到函数级别或代码块级别的事务控制。
这些函数可以以两种方式使用:
放在常用函数上,作为一个 装饰器 。例如:
from django.db import transaction@transaction.commit_on_success()def viewfunc(request): # ... # 在事务内执行的代码 # ...
这个功能在 Django 所支持的 Python 版本(大于等于 2.4 )中都可以使用。
作为一个环绕代码块的 环境管理器
from django.db import transactiondef viewfunc(request): # ... # 在缺省事务管理下运行的代码 # ... with transaction.commit_on_success(): # ... # 在一个事务内运行的代码 # ...
with 语句是 Python 2.5 新增的,所以这种方式只能用于 Python 2.5 版及以上版本。
为保证最大兼容,以下所有的例子均使用装饰器方式,但是所有例子都可以以环境管理器的方式使用。
Note
虽然以下例子使用视图函数来举例,但是这些装饰器和环境管理器可以在需要管理事务的任何地方使用。
- autocommit()¶
使用 autocommit 装饰器可以更换 Django 的缺省提交行为,使其有别于全局事务设定。
例如:
from django.db import transaction@transaction.autocommitdef viewfunc(request): ....@transaction.autocommit(using="my_other_database")def viewfunc2(request): ....
在 viewfunc() 中当调用 model.save() 、 model.delete() 或其他写数据库函数时,事务会立即提交。在viewfunc2() 中也会立即提交,但是使用的连接是"my_other_database" 。
- commit_on_success()¶
使用 commit_on_success 装饰器可以让同一个函数内的工作只使用一个事务:
from django.db import transaction@transaction.commit_on_successdef viewfunc(request): ....@transaction.commit_on_success(using="my_other_database")def viewfunc2(request): ....
如果函数成功返回,那么 Django 会提交该函数内的所有工作。如果函数产生一个异常,那么就会回滚这个事务。
- commit_manually()¶
如果你想完全控制事务,那么可以使用 commit_manually 装饰器。这个装饰器告诉 Django :我要自己动手管理事务。
如果你的视图改变了数据之后没有 commit() 或rollback() ,那么 Django 抛出一个TransactionManagementError 异常。
手动事务管理举例如下:
from django.db import transaction@transaction.commit_manuallydef viewfunc(request): ... # 你可以自由控制如何或何时提交或回滚 transaction.commit() ... # 但是不要忘记提交或回滚! try: ... except: transaction.rollback() else: transaction.commit()@transaction.commit_manually(using="my_other_database")def viewfunc2(request): ....
事务处理需求¶
Django 规定一个请求完成前每个开放的事务必须关闭。如果你使用 autocommit() (缺省的提交方式)或commit_on_success() ,那么这事是自动进行的,不用你操心。但是如果你手动管理事务(使用commit_manually() 装饰器),那么你必须确保在请求完成完成前,事务都已提交或回滚。
这个规则适用于所有数据库操作,而不仅仅是写操作。即使只是从数据库中读数据,事务也必须在请求完成之前提交或回滚。
如果全局性停用事务管理¶
在 Django 设置文件中设置 DISABLE_TRANSACTION_MANAGEMENT 为True 可以满足控制狂人停用所有事务管理的需求。
如果停用了,那么 Django 不会提供任何自动事务管理,中间件不会隐式提交事务,你得完全自己管理事务,甚至需要在其他地方使用中间件来提交变动。
因此,全局性停用事务管理适用于你想要运行自己的事务管理中间件的情况下,或者想做些奇怪的事情的情况下。绝大多数情况下,最好使用缺省的事务行为或使用事务中间件,根据需要修改函数。
保存点¶
保存点是事务中的一个标记,可以让你只回滚部分事务,而不是整个事务。 PostgreSQL 8 和 Oracle 支持保存点。其他数据库也提供保存点功能,但都是空操作,不做任何事情。
使用 Django 缺省的 autocommit 行为时,保存点是没用的。但当你使用commit_on_success 或commit_manually 时每个开放事务都会生成一系统数据库操作,并等待提交或回滚。如果你决定回滚,那么整个事务都会全部回滚。相对于执行transaction.rollback() 产生的全部回滚,保存点可以提供对回滚的细粒度控制。
以下每个函数都有一个提供被操作的数据库名称的 using 参数。如果没有提供这个参数,那么就会使用"缺省" 数据库。
保存点被事务对象上的三个方法控制:
- transaction.savepoint(using=None)¶
创建一个新的保存点,在事务中作了一个标记,表明当前状态“良好”。
返回的是保存点 ID ( sid )。
- transaction.savepoint_commit(sid,using=None)¶
更新保存点,把自上次设置保存点或上次提交之后的动作包括进来。
- transaction.savepoint_rollback(sid,using=None)¶
回滚至上一个提交的保存点。
以下例子演示如何使用保存点:
from django.db import transaction@transaction.commit_manuallydef viewfunc(request): a.save() # 开放事务现在包含 a.save() sid = transaction.savepoint() b.save() # 开放事务现在包含 a.save() 和 b.save() if want_to_keep_b: transaction.savepoint_commit(sid) # 开放事务还是包含 a.save() 和 b.save() else: transaction.savepoint_rollback(sid) # 开放事务现在只包含 a.save() transaction.commit()
MySQL 中的事务¶
如果你使用 MySQL ,那么能否使用事务取决于你的 MySQL 版本和你使用的数据库表的类型(指 "InnoDB" 或 "MyISAM" 这类的东西)。 MySQL 事务的讨论不在本文范围内,请转至MySQL 事务信息.
如果你的 MySQL 不 支持事务,那么 Django 会转为自动提交模式。如果支持就会象上文所述运作。
(现在我本地是mysql数据库,版本是5.0.15,mysql-5.0.15-win32.exe,经查此版本mysql数据库支持数据库事务,数据库表的类型也就是数据库引擎必须要选择InnoDB)
处理 PostgreSQL 事务中的异常¶
当调用一个 PostgreSQL 指针产生异常(典型异常为 IntegrityError )时,同一事务中所有后续 SQL 都会失效出错。出错信息为“当前事务已中止,事务内查询已失效”。在 PostgreSQL 中,简单的使用save() 一般不会产生异常。异常更多会发生在使用一些高级用法的时候,如使用唯一字段保存对象时、使用 force_insert/force_update 保存对象时或使用自定义 SQL 时。
有几种方法可以从错误中恢复。
事务回滚¶
第一种方法是回滚整个事务。例如:
a.save() # 成功,但可通过事务回滚恢复try: b.save() # 会抛出异常except IntegrityError: transaction.rollback()c.save() # 成功,但 a.save() 可能已被恢复
调用 transaction.rollback() 可回滚整个事务。在这个例子中,即使a.save() 本身没有出错其所做的变动也会被恢复。
保存点回滚¶
如果你使用 PostgreSQL 8 或更新版本,你可以使用 保存点 来控制回滚的范围。在执行有可能出错的数据库操作前,可以设置或更新保存点。这样就可以只回滚单个操作,而不用回滚整个事务。例如:
a.save() # 成功,不会被保存点回滚恢复try: sid = transaction.savepoint() b.save() # 会抛出异常 transaction.savepoint_commit(sid)except IntegrityError: transaction.savepoint_rollback(sid)c.save() # 成功, a.save() 没有被恢复
在这个例子中, a.save() 不会因为b.save() 抛出一个异常而恢复。
数据库级别的自动提交¶
在 PostgreSQL 8.2 版本或更新版本中,有一个高级选项可以运行以 数据库级别自动提交 方式运行 PostgreSQL 。如果你使用了这个选项,那么就不会有持续的事务,所以捕获异常后总是还可以继续。例如:
a.save() # 成功try: b.save() # 会抛出异常except IntegrityError: passc.save() # 成功
Note
这和 自动提交装饰器 有所不同。当使用数据库级别自动提交时,根本就不存在事务。而使用 autocommit 装饰器时还是使用事务的,只是当数据库修改指针时自动提交事务罢了。
- django官方文档——管理数据库事务
- django官方文档——模型与数据库
- django官方文档——管理器(数据库操作接口)
- django官方文档——使用多个数据库
- django官方文档——数据库访问优化
- django官方文档——管理器(数据库操作接口)
- django官方文档——Django settings
- django官方文档——统计查询
- django官方文档——发送邮件
- django官方文档——Settings详解
- django官方文档——统计查询
- django官方文档——构造查询(数据库查询 查询数据库)
- django官方文档——django中的用户认证
- django官方文档——执行原始sql查询
- django官方文档——模型字段关系参考
- django官方文档——Model 的 Meta 选项
- django 1.8 官方文档翻译: 3-3-4 管理文件
- django 1.8 官方文档翻译:13-1-3 密码管理
- Web.config中的特殊字符
- MinHash算法
- Java反射编程的小例子
- linux的system () 函数详解
- 为何Google比苹果和微软更需要HTML5?
- django官方文档——管理数据库事务
- android的Environment类
- Speex manul(手册)中文版
- SQL注入法攻击一日通
- SimHash算法
- 最简单的实现ajax提交和获取
- 深入了解Java的String
- django官方文档——使用多个数据库
- XCode中gdb调试技巧