django版本:1.8+, 数据库: mysql
事务:事务是一系列数据库语句的原子集。即使程序在运行时崩溃了,数据库可以确保事物集中的所有变更要么都被提交,要么都被放弃。
我们知道mysql数据库支持多种存储引擎。如MYISAM和innodb。在mysql5.5.5之后,innodb为mysql的默认存储引擎。innodb特点就是支持事务操作和外键约束。这里记录下django对数据库事务的api使用,假设我们使用的是innodb。如果数据库不支持事务操作的话, 那么Django会一直工作在自动提交模式 : 语句一旦被调用就会被执行和提交。
1. 可以在settings.py文件中的数据库配置加上配置项ATOMIC_REQUESTS:True。 这样的话,django在调用一个view里面的方法之前,django开始一个事务如果view执行的响应没有问题, Django就会提交这个事务。如果在view这里产生一个异常,Django就会回滚这次事务。
配置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'db_name', # Or path to database file if using sqlite3.
# The following settings are not used with sqlite3:
'USER': 'user',
'PASSWORD': 'password',
'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
'PORT': '', # Set to empty string for default.
# 'ATOMIC_REQUESTS': True , # 当需要将每个HTTP 请求封装在一个数据库事务中时,设置它为True
# 'AUTOCOMMIT': False, # 如果你需要禁用Django 的事务管理并自己实现,设置它为False。默认为True,
# 'CONN_MAX_AGE': 0, # 数据库连接的存活时间,以秒为单位。0 表示在每个请求结束时关闭数据库连接 —— 这是Django 的历史遗留行为, None 表示无限的持久连接。
},
'OPTIONS': {
'init_command': 'SET storage_engine=INNODB',
'charset': 'utf8mb4'
}
}
如果某个视图不想有事务管理,可以通过@non_atomic_requests()修饰view函数,这样的话,这个view函数执行逻辑就是autocommit。
@non_atomic_requests()
def helloworld(request):
if 'method' in request.GET:
if request.GET['method'] == 'new':
Book.objects.create(title=request.GET['title'])
if request.GET['title'] == 'error':
raise Exception("error")
return HttpResponse("helloworld")
这样的话,这个views将autocommit,Book.objects.create(title=request.GET['title'])执行时将直接commit到数据库。
2. 不通过上面的方式配置ATOMIC_REQUESTS。django的django.db.transaction提供了多个方式管理事务。主要的是atomic。我们可以使用@atomic修饰相应的视图函数,或者可以使用上下文管理器只在一段代码段进行事务管理。
@atomic()
def helloworld(request):
if 'method' in request.GET:
if request.GET['method'] == 'new':
Book.objects.create(title=request.GET['title'])
if request.GET['title'] == 'error':
raise Exception("error")
return HttpResponse("helloworld")
请求helloworld?method=new&title=error的话。Book.objects.create(title=request.GET['title'])将不会提交到数据库。
atomic()可以多层嵌套。最外面一层atomic()执行时,django将在数据库连接上设置in_atomic_block为True,使用set_autocommit(False)开始一个事务。非最外层的atomic()执行时,因为in_atomic_block已经为True,就会savepoint()创建保存点。 推出时,也是一层层commit或者rollback。