Django - ORM - 事务, 乐观锁, 悲观锁
事务
概念
Transaction
事务:一个最小的不可再分的工作单元;通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元)
一个完整的业务需要批量的DML(insert、update、delete)语句共同联合完成
事务只和DML语句 ( 数据库操作语句 ) 有关,或者说DML语句才有事务。这个和业务逻辑有关,业务逻辑不同,DML语句的个数不同
特性
▧ 原子性(A) 事务是最小单位,不可再分
▧ 一致性(C) 事务要求所有的DML语句操作的时候,必须保证同时成功或者同时失败
▧ 隔离性(I) 事务A和事务B之间具有隔离性
▧ 持久性(D) 是事务的保证,事务终结的标志(内存的数据持久到硬盘文件中)
行为
▧ 开启事务 Start Transaction
▧ 事务结束 End Transaction
▧ 提交事务 Commit Transaction
▧ 回滚事务 Rollback Transaction
标志
开启标志
任何一条DML语句(insert、update、delete)执行,标志事务的开启
结束标志
▧ 提交 成功的结束,将所有的DML语句操作历史记录和底层硬盘数据来一次同步
▧ 回滚 失败的结束,将所有的DML语句操作历史记录全部清空
代码库
Django 自带的代码库
from django.db import transaction
使用
方式一, 直接使用将一段操作设置为事务
with transaction.atomic():
...
方式二, 装饰器方式
@transaction.atomic
def foo():
....
悲观锁
概念
总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加锁(读锁、写锁、行锁等)
当其他线程想要访问数据时,都需要阻塞挂起。可以依靠数据库实现,如行锁、读锁和写锁等,都是在操作之前加锁
保证同一时刻只有一个线程能操作数据,其他线程则会被 block
运用场景
▧ 无脏读 上锁数据保证一致, 因此无脏读, 对脏读不允许的环境悲观锁可以胜任
▧ 无并行 悲观锁对事务成功性可以保证, 但是会对数据加锁导致无法实现数据的并行处理.
▧ 事务成功率高 上锁保证一次成功, 因此在对数据处理的成功率要求较高的时候更适合悲观锁.
▧ 开销大 悲观锁的上锁解锁是有开销的, 如果超大的并发量这个开销就不容小视, 因此不适合在高并发环境中使用悲观锁
▧ 一次性完成 如果乐观锁多次尝试的代价比较大,也建议使用悲观锁, 悲观锁保证一次成功
实例
from django.shortcuts import render
from django.http import HttpResponse
from django.views.generic import View
from django.db import transaction
from 应用名.models import 模型类名 # 类视图 (并发,悲观锁)
class MyView(View): @transaction.atomic
def post(self, request):
# select * from 表名 where id=1 for update;
# for update 就表示锁,只有获取到锁才会执行查询,否则阻塞等待。
obj = 模型类名.objects.select_for_update().get(id=1) # 等事务提交后,会自动释放锁。 return HttpResponse('ok')
乐观锁
概念
总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁
但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制或CAS操作实现。
如果发现数据被改了. 就进行事务回滚取消之前的操作
运用场景
▧ 脏读 乐观锁不涉及到上锁的处理, 因此在数据并行需求的时候是更适合乐观锁,当然会产生脏读, 不过用回滚取消掉了.
▧ 高并发 相比起悲观锁的开销, 乐观锁也是比悲观锁更适合于高并发场景
▧ 事务成功率低 乐观锁不能保证每次事务的成功, 是使用回滚方式来保证数据一致性, 因此会导致事务成功率很低.
▧ 读多写少 乐观锁适用于读多写少的应用场景,这样可以提高并发粒度
▧ 开销小 可能会导致很多次的回滚都不能拿到正确的处理回应, 因此如果对成功性要求低,而且每次开销小比较适合乐观锁
实例
from django.shortcuts import render
from django.http import JsonResponse
from django.views.generic import View
from django.db import transaction
from 应用名.models import GoodsSKU # 类视图 (并发,乐观锁)
class MyView(View): @transaction.atomic
def post(self, request):
'''订单创建'''
count = 3 # 订购3件商品 # 设置事务保存点
s1 = transaction.savepoint() # 乐观锁,最多尝试5次
for i in range(5):
# 查询商品的信息(库存)
try:
sku = GoodsSKU.objects.get(id=1)
except:
# 商品不存在
transaction.savepoint_rollback(s1)
return JsonResponse({'res': 1, 'errmsg': '商品不存在'}) # 判断商品的库存
if count > sku.stock:
transaction.savepoint_rollback(s1)
return JsonResponse({'res': 2, 'errmsg': '商品库存不足'}) # 更新商品的库存和销量
orgin_stock = sku.stock # 原库存 (数据库隔离级别必须是Read Committed;如果是Repeatable Read,那么多次尝试读取的原库存都是一样的,读不到其他线程提交更新后的数据。)
new_stock = orgin_stock - count # 更新后的库存
new_sales = sku.sales + count # 更新后的销量 # update 商品表 set stock=new_stock, sales=new_sales where id=1 and stock = orgin_stock
# 通过where子句中的条件判断库存是否进行了修改。(并发,乐观锁)
# 返回受影响的行数
res = GoodsSKU.objects.filter(id=1, stock=orgin_stock).update(stock=new_stock, sales=new_sales)
if res == 0: # 如果修改失败
if i == 4:
# 如果尝试5次都失败
transaction.savepoint_rollback(s1)
return JsonResponse({'res': 3, 'errmsg': '下单失败'})
continue # 再次尝试 # 否则更新成功
# 跳出尝试循环
break # 提交事务
transaction.savepoint_commit(s1) # 返回应答
return JsonResponse({'res': 4, 'message': '创建成功'})
Django - ORM - 事务, 乐观锁, 悲观锁的更多相关文章
- Java并发 行级锁/字段锁/表级锁 乐观锁/悲观锁 共享锁/排他锁 死锁
原文地址:https://my.oschina.net/oosc/blog/1620279 前言 锁是防止在两个事务操作同一个数据源(表或行)时交互破坏数据的一种机制. 数据库采用封锁技术保证并发操作 ...
- 最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁
在Java并发场景中,会涉及到各种各样的锁如公平锁,乐观锁,悲观锁等等,这篇文章介绍各种锁的分类: 公平锁/非公平锁 可重入锁 独享锁/共享锁 乐观锁/悲观锁 分段锁 自旋锁 01.乐观锁 vs 悲观 ...
- 乐观锁悲观锁对应的JAVA代码和数据库
乐观锁悲观锁是一种思想.可以用在很多方面. 比如数据库方面.悲观锁就是for update乐观锁就是 version字段 JDK方面:悲观锁就是sync乐观锁就是原子类(内部使用CAS实现) 本质来说 ...
- AtomicInteger如何保证线程安全以及乐观锁/悲观锁的概念
众所周知,JDK提供了AtomicInteger保证对数字的操作是线程安全的,线程安全我首先想到了synchronized和Lock,但是这种方式又有一个名字,叫做互斥锁,一次只能有一个持有锁的线程进 ...
- Java中的锁-悲观锁、乐观锁,公平锁、非公平锁,互斥锁、读写锁
总览图 如果文中内容有错误,欢迎指出,谢谢. 悲观锁.乐观锁 悲观锁.乐观锁使用场景是针对数据库操作来说的,是一种锁机制. 悲观锁(Pessimistic Lock):顾名思义,就是很悲观,每次去拿数 ...
- Mysql锁机制--乐观锁 & 悲观锁
Mysql 系列文章主页 =============== 从 这篇 文章中,我们知道 Mysql 并发事务会引起更新丢失问题,解决办法是锁.所以本文将对锁(乐观锁.悲观锁)进行分析. 第一部分 悲观锁 ...
- MySQL 乐观锁 悲观锁 共享锁 排他锁
乐观锁 乐观锁是逻辑概念上的锁,不是数据库自带的,需要我们自己去实现.乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁 ...
- 乐观锁&悲观锁
悲观&乐观,只是对数据加锁的时机与粒度. 悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这 ...
- Java并发之乐观锁悲观锁
定义 乐观锁和悲观锁这两种锁机制,是在多用户环境并发控制的两种所机制. 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作.[1]常见实现如独占锁.乐观锁:假设不会发生并发冲突,只在提交操作 ...
随机推荐
- openstack安装部署——计算服务(控制节点&计算节点)前言
1.前言Openstack计算服务通过认证服务获取认证:通过镜像服务获取镜像:通过仪表盘提供的用户界面与用户交互.镜像的存取受工程和用户的限制,配额受工程的限制(例如不同工程允许虚拟机实例数量不同). ...
- Xen 虚拟化技术
Xen 是一种开源的.属于类型1(裸金属虚拟化,Baremetal Hypervisor)的虚拟化技术,它使多个同样操作系统或不同操作系统的虚拟机运行在同一个物理主机节点上成为可能并实现. Xen 是 ...
- 机器学习(十)—聚类算法(KNN、Kmeans、密度聚类、层次聚类)
聚类算法 任务:将数据集中的样本划分成若干个通常不相交的子集,对特征空间的一种划分. 性能度量:类内相似度高,类间相似度低.两大类:1.有参考标签,外部指标:2.无参照,内部指标. 距离计算:非负性, ...
- 一个页面,WEB全功能
当鼠标在页面上往下滑动的时候,页面也一直向下,标签也顺带着全部向下滑动 以前浏览页面,主要是在PC上进行浏览,一个页面不适于太长,需要用户向下拖动: 当时的设计是,点击标签,点击不同的标签,跳转到不同 ...
- PAT Basic 1089 狼人杀-简单版 (20 分)
以下文字摘自<灵机一动·好玩的数学>:“狼人杀”游戏分为狼人.好人两大阵营.在一局“狼人杀”游戏中,1 号玩家说:“2 号是狼人”,2 号玩家说:“3 号是好人”,3 号玩家说:“4 号是 ...
- #2002 Cannot log in to the MySQL server, PHPMyAdmin/MySQL
改完会可能会出现1045的错误 在phpStudy中,其他选项菜单——mysql工具——重置密码,即可
- linux实操_shell自定义函数
基本语法: #定义函数 function 函数名(){ 函数体 } #调用函数 函数名 参数1 参数2... 实例:计算两个数的和. 运行后
- 现代浏览器性能优化-CSS篇
我来填坑了,CSS篇终于写出来了,如果你没看过前面的JS篇,可以在这里观看. 众所周知,CSS的加载会阻塞浏览器渲染或是引起浏览器重绘,目前业界普遍推荐把CSS放到<head>中,防止在C ...
- Display Tag Lib Table进行分页
Display Tag Lib是一个标签库,用来处理jsp网页上的Table,功能非常强,可以对的Table进行分页.数据导出.分组.对列排序等等,反正我在做项目时需要的功能它都给我提供了,而且使用起 ...
- 「数据结构与算法(Python)」(二)
顺序表 在程序中,经常需要将一组(通常是同为某个类型的)数据元素作为整体管理和使用,需要创建这种元素组,用变量记录它们,传进传出函数等.一组数据中包含的元素个数可能发生变化(可以增加或删除元素). 对 ...