django的update和create高级操作

0. 介绍

方法

get_or_create   

如果存在就返回,不存在就先创建再返回,返回值有两个,一个是操作的 model 实例,一个是是否是 cre    ated 的 布尔型数据update_or_create

select_for_update

一定要配合事务使用,会等待行锁释放之后,返回查询结果

bulk_create

批量创建

bulk_update

群更新

models.py

from django.db import models


# Create your models here.


class Text_one(models.Model):
    title = models.CharField(max_length=225)
    name = models.CharField(max_length=225, db_index=True)
    count = models.IntegerField(default=100)

get_or_create

介绍

这个函数的返回值有两个,一个是操作的 model 实例,一个是是否是 created 的 布尔型数据

参数defaults:model 除了name,这个字段,还有其他的字段,创建数据的时候,给不在查询条件内的字段,设置的默认值

注意: 查询的条件必须是唯一的,否则会造成多条数据返回而报错,这个逻辑同 get() 函数。

注意: 使用的字段,没有唯一的约束,并发的调用这个方法可能会导致多条相同的值插入。

示例

def t1(request):
    instance, create = models.Text_one.objects.get_or_create(name='天衣无缝1', defaults={
        'title': '天意'
    })
    print('instance', instance)
    print('create', create)
    # instance Text_one object (4)
    # create True
    return HttpResponse('ok')

update_or_create

介绍

存在的字段话,更新default字段内的内容·,不存在的话,就创建该数据。

示例

from django.shortcuts import render, HttpResponse

from . import models


def t1(request):
    instance, create = models.Text_one.objects.update_or_create(name='天衣无缝5', defaults={
        'title': '天意66',
    })
    print('instance', instance)
    print('create', create)
    return HttpResponse('ok')

select_for_update

事务操作

(22条消息) mysql在django中开启事务,实现悲观锁和乐观锁_骑台风走的博客-CSDN博客https://blog.csdn.net/qq_52385631/article/details/126899229?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22126899229%22%2C%22source%22%3A%22qq_52385631%22%7D

介绍

1. 在django中使用,一定需要与事务连用,不然不起作用,作为悲观锁思想的排它锁实现方式,从粒度来看本质是行锁,用来解决mysql并发问题

2. 场景上,比如火车票订票,在屏幕上显示票量,而真正进行出票时,需要重新确定一下这个数据没有被其他客户端修改。所以,在这个确认过程中,可以使用for update。这是统一的解决方案方案问题,需要前期有所准备。

其他介绍:

1. 在我们的查询器上使用select_for_update来告诉数据库锁定对象,直到事务完成。
2. 在数据库中锁定一行需要一个数据库事务 - 我们使用Django的装饰器transaction.atomic来开启事务。

参数:

这个方法有两个默认参数,nowait=False 和 skip_locked=False

nowait=True的含义是匹配的记录被锁时不等待,直接抛异常。

skip_locked=True的含义是SELECT时跳过被锁的记录。

注意:MySQL版本要在8.0.1+ 以上才支持 nowait,skip_locked和of选项。

注意:在mysql加锁,依旧出现并发修改,原因如下:
1、必须置于事务中,事务要能生效,特别是spring中事务方法必须是public,且必须是由类外调用该事务方法。
2、for update的查询语句必须规范,要么查询条件是主键,要么查询条件要走索引,至于最终是锁行还是锁表都有可能。
3、如果有读写分离中间件,必须保证for update到主库,因为一般从库都是read-only( for update语句在read-only环境中会报错) 3. 线上环境均满足以上条件,且做测试发现能排它锁运行正常。最终找到原因为在线上分布式环境中开启了mybatis的二级缓存。

示例


from . import models
from django.db.models import Max, F
from time import sleep
from django.db import transaction


def t2(request):
    # 创建保存点
    # # 开启事务,当方法执行完以后,自动提交事务
    with transaction.atomic():
        sid = transaction.savepoint()
        try:
            # 锁住当前查询到的符合数据,锁住记录后其他的事务无法操作,等当前事务执行完,才允许别的事务进行操作
            instance = models.Text_one.objects.select_for_update().filter(id=1)
            print(instance)
            if instance.count() >= 100 or instance.count() < 150:
                models.Text_one.objects.filter(name='小宝').update(count=F('count') + 1)
        except Exception:
            print('ss')
            transaction.savepoint_rollback(sid)
    return HttpResponse('ok2')

bulk_create

介绍

1. 批量创建

2. 如果我们批量创建的数量过多,我们可以指定分批次来创建,通过 batch_size 参数来指定。

示例

from rest_framework.views import APIView
from rest_framework.response import Response
from . import models
 
# models
class UserInfo(models.Model):
    username = models.CharField(max_length=66)
 
# url
path('t3/', views.T3.as_view()),
 
# view
class T3(APIView):
    authentication_classes = []
 
    def get(self, request):
        userinfo_data = []
        for i in range(10):
            # 先生成对象
            user = models.UserInfo(username=i)
            print("user", user) # user UserInfo object
            userinfo_data.append(user)
        # 群增,分两次创建
        models.UserInfo.objects.bulk_create(userinfo_data,batch_size=2)
        return Response('ok')

bulk_update

介绍

1. 群修改

2. 需要注意的是 bulk_update 多了个参数,fields 这个是用来指定需要更新的字段。

3. 如我们下面所示,我们指定更新的是 name 字段,那么就算我们,更改了 title的数据,只要 fields 列表里没有指定该字段,那么数据库也不会更新该字段。

示例


from . import models


def t1(request):
    instance = models.Text_one.objects.all()
    for article in instance:
        article.name = "name_updated"
        article.title = "title_updated"
    models.Text_one.objects.bulk_update(instance, fields=['name'], batch_size=2)
    return HttpResponse('ok1')

其他

源码

# 源码
def select_for_update(self, nowait=False, skip_locked=False):
    """
    Returns a new QuerySet instance that will select objects with a
    FOR UPDATE lock.
    """
    if nowait and skip_locked:
        raise ValueError('The nowait option cannot be used with skip_locked.')
    obj = self._clone()
    obj._for_write = True
    obj.query.select_for_update = True
    obj.query.select_for_update_nowait = nowait
    obj.query.select_for_update_skip_locked = skip_locked
    return obj

参考文章

(2条消息) Django笔记十三之select_for_update等选择和更新等相关操作_vv安的浅唱的博客-CSDN博客_django select_for_updatehttps://blog.csdn.net/weixin_43354181/article/details/123697817(9条消息) Django中select_for_update方法的应用_˚天霸动霸Tua的博客-CSDN博客_django select_for_updatehttps://blog.csdn.net/kaikai0803/article/details/97278180
(12条消息) mysql开启事务和加锁(django)_骑台风走的博客-CSDN博客_django mysql事务https://blog.csdn.net/qq_52385631/article/details/122869771?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166332855416800182720785%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=166332855416800182720785&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-2-122869771-null-null.nonecase&utm_term=transaction.atomic&spm=1018.2226.3001.4450

 (12条消息) mysql开启事务和加锁(django)_骑台风走的博客-CSDN博客_django mysql事务https://blog.csdn.net/qq_52385631/article/details/122869771?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166332559116782427429565%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=166332559116782427429565&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-2-122869771-null-null.nonecase&utm_term=transaction.atomic%28%29&spm=1018.2226.3001.4450

(12条消息) 04、django高并发连接数据库的并发控制问题 和 简单代码测试_鞍-的博客-CSDN博客_django并发控制https://blog.csdn.net/weixin_41097516/article/details/113483346?utm_source=app&app_version=5.2.1&code=app_1562916241&uLinkId=usr1mkqgl919blen (14条消息) select...for update使用方法_鲨鱼辣椒灬的博客-CSDN博客_select…for updatehttps://blog.csdn.net/ll594317566/article/details/103869619

猜你喜欢

转载自blog.csdn.net/qq_52385631/article/details/126893275