行级锁
select_for_update(nowait=False, skip_locked=False) #注意必须用在事务里面,至于如何开启事务,我们看下面的事务一节。
返回一个锁住行直到事务结束的查询集,如果数据库支持,它将生成一个 SELECT … FOR UPDATE 语句。
举个例子:
entries = Entry.objects.select_for_update().filter(author=request.user) #加互斥锁,由于mysql在查询时自动加的是共享锁,所以我们可以手动加上互斥锁。create、update、delete操作时,mysql自动加行级互斥锁
所有匹配的行将被锁定,直到事务结束。这意味着可以通过锁防止数据被其它事务修改。
一般情况下如果其他事务锁定了相关行,那么本查询将被阻塞,直到锁被释放。 如果这不想要使查询阻塞的话,使用select_for_update(nowait=True)。 如果其它事务持有冲突的锁,互斥锁, 那么查询将引发 DatabaseError 异常。你也可以使用select_for_update(skip_locked=True)忽略锁定的行。 nowait和 skip_locked是互斥的,同时设置会导致ValueError。
目前,postgresql,oracle和mysql数据库后端支持select_for_update()。 但是,MySQL不支持nowait和skip_locked参数。
使用不支持这些选项的数据库后端(如MySQL)将nowait=True或skip_locked=True转换为select_for_update()将导致抛出DatabaseError异常,这可以防止代码意外终止。
关于MySQL的事务处理,我上面的mysql博客已经说的很清楚了,那么我们来看看Django是如果做事务处理的。django1.8版本之前是有很多种添加事务的方式的,中间件的形式(全局的)、函数装饰器的形式,上下文管理器的形式等,但是很多方法都在1.8版之后给更新了,下面我们只说最新的三种方式:
在Web应用中,常用的事务处理方式是将每个请求都包裹在一个事务中。这个功能使用起来非常简单,你只需要将它的配置项ATOMIC_REQUESTS设置为True。
它是这样工作的:当有请求过来时,Django会在调用视图方法前开启一个事务。如果请求却正确处理并正确返回了结果,Django就会提交该事务。否则,Django会回滚该事务。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mxshop',
'HOST': '127.0.0.1',
'PORT': '3306',
'USER': 'root',
'PASSWORD': '123',
'OPTIONS': {
"init_command": "SET default_storage_engine='INNODB'",
#'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", #配置开启严格sql模式
}
"ATOMIC_REQUESTS": True, #全局开启事务,绑定的是http请求响应整个过程
"AUTOCOMMIT":False, #全局取消自动提交,慎用
},
'other':{
'ENGINE': 'django.db.backends.mysql',
......
} #还可以配置其他数据库
}
上面这种方式是统一个http请求对应的所有sql都放在一个事务中执行
(要么这个http请求成功,要么这个http请求失败,对数据库不产生任何影响)。
from django.db import transaction
@transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()
整个视图函数为一个事务!
from django.db import transaction
def viewfunc(request):
with transaction.atomic(): # 保存点
# This code executes inside a transaction.
do_more_stuff()
with transaction.atomic()下的缩进部分为一个事务!