Django orm中的事务和锁x

锁:

行级锁:

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()

待续....

上一篇:Django 中间件

下一篇:标签绑定事件的几种方式