锁:
行级锁:
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(skil_locked=True)忽略锁定的行。但注意 nowait 和skip_locked是互斥的,不能同时使用。
postgresql,oracle,mysql都支持select_for_update(),但mysql不支持nowait, skip_locked参数。
事务
全局开启:要全局开启事务,你只需要将它的配置项ATOMIC_REQUESTS设置为True。工作原理是,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放行时,可以使用non_atomic_requests装饰器。
from django.db import transaction
@transaction.non_atomic_requests
def my_view(request):
do_stuff()
@transaction.non_atomic_requests(using='other')
def my_other_view(request):
do_stuff_on_the_other_database()
它会在一定程序上影响性能,所以推荐局部使用事务。
局部使用事务
atomic(using=None, savepoint=True)[souce],参数using='other',就是当你操作其他数据库时,这个事务才生效,savepoint的意思是开启事务保存点。
atomic管理的代码块可以内嵌到说法中,当内部代码正常运行,但外部代码出现异常,它也没法将修改提交到数据库。
有种方法来使用局部事务
装饰器
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):
# This code executes in autocommit mode (Django's default).
do_stuff()
with transaction.atomic(): # 保存点
# This code executes inside a transaction.
do_more_stuff()
do_other_stuff()
嵌套使用:
from django.db import IntegrityError, transaction
@transaction.atomic
def viewfunc(request):
create_parent()
try:
with transaction.atomic():
generate_relationships()
# other_task()
# #还要注意一点,如果你在事务里面写了别的操作,只有这些操作全部完成之后,事务才会commit,
# 也就是说,如果你这个任务是查询上面更改的数据表里面的数据,那么看到的还是事务提交之前的数据。
except IntegrityError:
handle_exception()
add_children()
待续....