如何在 Django 中保证并发的数据一致性
1. 关于锁
1.1 乐观锁
乐观锁的出发点是,同一条数据很少会因为并发修改而产生冲突,适用于读多写少的场景,用以提高吞吐量。
实现方式,读取一个字段,执行处理逻辑,当需要更新数据时,再次检查该字段是否和第一次读取一致。如果一致,则更新数据,否则拒绝更新,重新读取后再提交。
1.2 悲观锁
悲观锁的出发点是,当一条数据正在被修改时,不允许其他任何关于这条数据的操作。
实现方式,读取一个字段之后,加锁,不允许其他任何读、写操作。执行处理逻辑,更新数据完毕后,释放锁。
1.3 比较
乐观锁的开销远低于悲观锁。
悲观锁可能会导致死锁。当 A 锁定了 a 资源,需要 b 资源。而 b 被 B 锁定,正在等待 a 资源。此时,导致出现死锁。但是,可以通过设置超时来处理这个问题。
悲观锁可以有效降低冲突后,重试的次数。
乐观锁可以提高响应速度。
2. Django 中的事务
Django 默认每条数据库操作都会被立即提交到数据库。
这样会导致一个问题,如果有一系列的数据库操作构成,要么全部执行,要么就全部都不执行,怎么办?
这时,就需要事务。将一系列数据库操作设置为一个事务,提交给数据库执行。
Django 提供 atomic 装饰器以开启事务。 atomic 使用一个参数来指定数据库的名字。如果不设置值,Django 就会使用系统默认的数据库。
2.1 整个 View 函数开启事务
from django.db import transaction @transaction.atomic
def viewfunc(request):
# This code executes inside a transaction.
do_stuff()
2.2 部分函数 do_more_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()
2.3 不要在事务中处理异常
from django.db import transaction def viewfunc(request):
do_stuff()
try:
with transaction.commit_on_success():
do_more_stuff_1() # in transaction
try:
do_more_stuff_2() # not in transaction
except:
pass
do_more_stuff_3() # in transaction
except:
pass
当退出原子块时,Django 会查看它是否正常退出或者是否有异常来确定是否提交或者回滚。
如果你捕获并处理原子块中的异常,可以能会隐藏 Django 中发生问题的事实。这样可能会造成非预期的行为。
3. 利用 F 函数更新运算
通常更新数据库的操作,需要将对象读取到内存。在内存中进行修改之后,再写回数据库。
在内存中的操作,如果存在同时操作的情况,会导致运算逻辑错误。
F() 函数的作用就是直接生成 SQL 语句,不必将需要更新的对象读取到内存。避免了并发导致的数据不一致问题。
from django.db.models import F reporter = Reporters.objects.get(name='OICQ')
reporter.stories_filed = F('stories_filed') + 1
reporter.save()
4. 利用 select_for_update 函数
select_for_update 使用的是悲观锁。
select for update 函数使用数据库查询语句,select ... for update
对数据库进行操作。
这是数据库层面的,解决并发取数据后再修改的问题方法。
def mark_as_readed(self, notification_id):
# 让s elect for update 和 update 语句发生在一个完整的事务里面
with transaction.commit_on_success():
# 使用select_for_update 来保证并发请求同时只有一个请求在处理,其他的请求
# 等待锁释放
notification = Notification.objects.select_for_update().get(pk=notification_id)
# 没有必要重复标记一个已经读过的通知
if notication.has_readed:
return
notification.has_readed = True
notification.save()
# 在这里更新我们的计数器,嗯,我感觉好极了
self.update_unread_count(-1)
如何在 Django 中保证并发的数据一致性的更多相关文章
- Django中管理并发操作
上一篇我们说了,如何在Django中进行事务操作,数据的原子性操作 涉及了事务操作,我们不得不考虑的另一个问题就是:并发操作 还是那个用户转账的操作 我们使用事务操作解决的操作中途服务器宕机问题 但是 ...
- 【Django】Django如何保证并发操作数据一致性问题
代码示例: 使用 select for update 数据库查询 select ... for update 是数据库层面上专门用来解决并发取数据后再修改的场景的,主流的关系数据库 比如mysql.p ...
- 如何在Django中配置MySQL数据库
直接上图 在项目中直接找到settings 文件 第一步 原始Django自带数据库 第二步将配置改成MySQL的数据 第三步 在__init__文件中告知Django使用MySQL数据 ...
- 如何在django中使用多个数据库
http://blog.chinaunix.net/uid-16728139-id-4364343.html
- Django中的信号
信号 Django 提供一个“信号分发器”,允许解耦的应用在框架的其它地方发生操作时会被通知到. 简单来说,信号允许特定的sender通知一组receiver某些操作已经发生. 这在多处代码和同一事件 ...
- Django 中使用 Celery
起步 在 <分布式任务队列Celery使用说明> 中介绍了在 Python 中使用 Celery 来实验异步任务和定时任务功能.本文介绍如何在 Django 中使用 Celery. 安装 ...
- 「Python-Django」Django中使用数据库的 9 个小技巧
Django 中使用数据库的 9 个小技巧. 1. 过滤器聚合 在 Django 2.0 之前,如果你想得到“用户总数”.“活跃用户总数”等信息时,你不得不使用条件表达式. Django 2.0 中, ...
- 在Django中使用ORM创建图书管理系统
一.ORM(对象关系映射) 很多语言的web框架中都有这个概念 1. 为什么要有ORM? 1. 写程序离不开数据,要使用数据就需要连接数据库,但是不同的数据库在sql语句上(mysql,oracle等 ...
- Django中涉及金融的项目
在Django中,如果一个项目涉及了金融,他的要求是十分严格的. 所以嘞,这里就有一些坑,很多坑,第一次开发的时候很容易出现一系列的错误 在涉及金融计算的地方,不能使用float类型 什么鬼,但事实就 ...
随机推荐
- [Spring学习笔记 3 ] spring 注解详解,完全注解,常用注解
.xml使用注解 xml 用来定义bean的信息,注解用来配置依赖信息 ) 在配置文件中配置bean )在javaBean中用注解来指定依赖注入 )在配置文件中开启注解扫描 @Resource标签 j ...
- php数组使用json_encode函数中文被编码成null的原因和解决办法
大写的囧,提客户处理问题,前端的APP一直在叽叽咂咂,说收到的值是null,弄了半天原来是这个问题,记录下吧 json格式在开发中用的十分广泛.在php中json_encode函数可以直接将数组转成 ...
- scp的两种方式
如果host A 与 host B建立了信任连接(B有A的public key),那么从A向B传送文件,或者从B上传回文件都可以省略密码.但是前提是命令是在A上执行的. 从A向B拷贝文件 on hos ...
- 九款命令行工具助力Linux环境下的数据分析
对于大多数熟悉了图形工作环境的朋友来说,电子表格工具无疑是第一选项.但命令行工具同样能够更快更高效地解决问题——且只须稍微学习即可上手. 大部分此类工具冻严格局限于Linux,而多数可同样运行在Uni ...
- 老男孩linux实训学生入学资格考试题(技术部分)
################################################################ 本文内容摘录于老男孩linux实战运维培训中心入学考试题(答案部分) ...
- Android MD5校验码的生成与算法实现
在Java中,java.security.MessageDigest (rt.jar中)已经定义了 MD5 的计算,所以我们只需要简单地调用即可得到 MD5 的128 位整数.然后将此 128 位计 ...
- FluentValidation:C#后端输入验证框架的官方文档解读
参照 FluentValidation 的官方文档写的例子,方便日后查看和使用. 原文:https://github.com/JeremySkinner/FluentValidation/wiki H ...
- window 10 企业版激活
一. 用管理员权限打开CMD.EXE 接着输入以下命令: slmgr /ipk NPPR9-FWDCX-D2C8J-H872K-2YT43 弹出窗口提示:“成功的安装了产品密钥”. 继续输入以下命令: ...
- java php 等,路径 上级路径,上上级路径表示方法
如何表示上级目录 ../表示源文件所在目录的上一级目录,../../表示源文件所在目录的上上级目录,以此类推. ../表示源文件所在目录的上一级目录,../../表示源文件所在目录的上上级目录,以此类 ...
- hashCode和identityHashCode底层是怎么生成的
前言:在工作中使用==埋下的坑这篇博文的最后,我想到了两个问题,其中一个是——为什么 int int1=99;int int2=99;int1和int2的identityHashCode是 ...