django基础之ORM中的事务和锁
一.事务
1.全局开启
在Web应用中,常用的事务处理方式是将每个请求都包裹在一个事务中。这个功能使用起来非常简单,你只需要将它的配置项ATOMIC_REQUESTS设置为True。
它是这样工作的:当有请求过来时,Django会在调用视图方法前开启一个事务。如果请求却正确处理并正确返回了结果,Django就会提交该事务。否则,Django会回滚该事务。
操作方法:在settings文件中添加以下信息
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放水,可以用 "non_atomic_requests"修饰器
from django.db import transaction
@transaction.non_atomic_requests
def my_view(request):
do_stuff()
@transactions.non_atomic_requests(using='other') #这块的other是setting文件里面设置的别的数据库,在这块的意思是,当执行这个数据库的时候,这个函数不绑定事务
def my_other_view(request)::
do_staff_on_the_other_database()
注意:一般不推荐这么做,因为如果将事务跟 HTTP 请求绑定到一起的时,然而view 是依赖于应用程序对数据库的查询语句效率和数据库当前的锁竞争情况。当流量上来的时候,性能会有影响
2.局部使用事务(建议)
用法1:给函数做装饰器来使用
from django.db import transaction
@transaction.atomic
def viewfunc(request):
do_stuff()
用法2:作为上下文管理器来使用,其实就是设置'事务的保存点(SAVEPOINT)'---->实现局部回滚
from django.db import transaction
def viewfunc(request):
do_stuff()
with transaction.atomic(): #保存点
do_more_stuff() #实现这部分内容的回滚
do_other_stuff()
二.锁
行级锁
select_for_update(nowait=False, skip_locked=False) #注意必须用在事务里面,
例:
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参数。