get_or_create
如果存在就返回,不存在就先创建再返回,返回值有两个,一个是操作的 model 实例,一个是是否是 cre ated 的 布尔型数据update_or_create
select_for_update
一定要配合事务使用,会等待行锁释放之后,返回查询结果
bulk_create
批量创建
bulk_update
群更新
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)
这个函数的返回值有两个,一个是操作的 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')
存在的字段话,更新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')
(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')
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')
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