Django ORM 中安全处理并发更新的最佳实践
发布时间 - 2025-12-31 00:00:00 点击率:次在异步 telegram 机器人中使用 django orm 执行原子性扣减与累加操作时,需通过数据库级锁(如 `select_for_update`)和事务封装(`transaction.atomic`)避免竞态条件,推荐结合 `f()` 表达式实现无状态、线程/协程安全的字段更新。
Django ORM 完全适用于高并发场景下的数据一致性保障,但必须正确使用其并发控制机制。你示例中的代码存在两个关键风险点:一是 obj1.filed1 > 0 判断后到 save() 之间存在时间窗口,多请求可能同时通过判断并重复扣减;二是两次 save() 非原子操作,若中间出错会导致数据不一致。
✅ 推荐方案:事务 + select_for_update() + F() 表达式
from django.db import transaction
from django.db.models import F
async def on_button_click():
try:
with transaction.atomic():
# 使用 select_for_update() 加行级写锁(需确保数据库支持,如 PostgreSQL/MySQL InnoDB)
obj1 = Object1.objects.select_for_update().get(id=X)
if obj1.field1 >= N: # 注意:>= 避免扣成负数
# 原子更新:所有计算在数据库层面完成,无需读取-修改-写入(RMW)循环
Object1.objects.filter(id=X).update(field1=F('field1') - N)
Object2.objects.filter(id=X2).update(field2=F('field2') + N)
else:
raise ValueError("Insufficient balance")
except Object1.DoesNotExist:
raise ValueError("Object1 not found")
except Exception as e:
# 日志记录 & 用户反馈
logger.warning(f"Button click failed: {e}")
raise? 关键要点说明:
- transaction.atomic() 确保整个块为数据库事务,失败则回滚;
- select_for_update() 在 obj1 行上加排他锁,阻塞其他并发事务对该行的 SELECT ... FOR UPDATE 或 UPDATE,直到当前事务结束;
- F() 表达式使更新脱离 Python 层计算,直接由数据库执行(如 SET field1 = field1 - N),彻底规避读-改-写竞态;
- 锁定范围应精准:仅锁定实际参与更新的行(如 Object1.objects.select_for_update().get(id=X)),避免锁表或锁过多行影响性能;
- ⚠️ 注意:select_for_update() 在 SQLite 中不生效,在 MySQL 中需启用 READ-COMMITTED 或更高隔离级别,在 PostgreSQL 中默认支持;
? 异步兼容性提示:
Django 4.1+ 原生支持异步视图与 ORM 调用,但 select_for_update() 和 transaction.atomic() 目前仍要求同步上下文(即需在 sync_to_async 包装器中执行)。Pyrogram 的异步 handler 中应这样调用:
from asgiref.sync import sync_to_async # 在 async handler 中: await sync_to_async(on_button_click_sync)() # 其中 on_button_click_sync 是上述同步事务函数
? 替代思路(进阶):
若业务逻辑更复杂(如需校验多个条件、触发事件链),可考虑使用数据库原生 UPDATE ... RETURNING(PostgreSQL)或乐观锁(添加 version 字段 + WHERE version = old_version 条件更新),但对绝大多数余额类场景,atomic + select_for_update + F() 组合已足够健壮、简洁且可维护。
# mysql
# python
# go
# ai
# django
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
EditPlus中的正则表达式 实战(1)
Laravel辅助函数有哪些_Laravel Helpers常用助手函数大全
网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?
标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?
如何在服务器上配置二级域名建站?
Laravel怎么创建自己的包(Package)_Laravel扩展包开发入门到发布
Laravel如何使用Guzzle调用外部接口_Laravel发起HTTP请求与JSON数据解析【详解】
Laravel如何配置和使用队列处理异步任务_Laravel队列驱动与任务分发实例
宙斯浏览器视频悬浮窗怎么开启 边看视频边操作其他应用教程
javascript基本数据类型及类型检测常用方法小结
Laravel如何处理和验证JSON类型的数据库字段
如何用虚拟主机快速搭建网站?详细步骤解析
jQuery 常见小例汇总
微信小程序 配置文件详细介绍
如何在建站之星绑定自定义域名?
阿里云高弹*务器配置方案|支持分布式架构与多节点部署
千问怎样用提示词获取健康建议_千问健康类提示词注意事项【指南】
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
如何正确选择百度移动适配建站域名?
Laravel如何使用Spatie Media Library_Laravel图片上传管理与缩略图生成【步骤】
网站制作免费,什么网站能看正片电影?
Microsoft Edge如何解决网页加载问题 Edge浏览器加载问题修复
千库网官网入口推荐 千库网设计创意平台入口
浅谈Javascript中的Label语句
网易LOFTER官网链接 老福特网页版登录地址
Laravel怎么生成二维码图片_Laravel集成Simple-QrCode扩展包与参数设置【实战】
如何在IIS服务器上快速部署高效网站?
想要更高端的建设网站,这些原则一定要坚持!
laravel怎么在请求结束后执行任务(Terminable Middleware)_laravel Terminable Middleware请求结束任务执行方法
Laravel如何使用Socialite实现第三方登录?(微信/GitHub示例)
HTML5段落标签p和br怎么选_文本排版常用标签对比【解答】
html5的keygen标签为什么废弃_替代方案说明【解答】
微信h5制作网站有哪些,免费微信H5页面制作工具?
Laravel如何正确地在控制器和模型之间分配逻辑_Laravel代码职责分离与架构建议
香港服务器WordPress建站指南:SEO优化与高效部署策略
进行网站优化必须要坚持的四大原则
javascript基于原型链的继承及call和apply函数用法分析
网站制作企业,网站的banner和导航栏是指什么?
JS中页面与页面之间超链接跳转中文乱码问题的解决办法
Windows10电脑怎么查看硬盘通电时间_Win10使用工具检测磁盘健康
移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?
如何在宝塔面板中创建新站点?
如何在橙子建站中快速调整背景颜色?
晋江文学城电脑版官网 晋江文学城网页版直接进入
专业商城网站制作公司有哪些,pi商城官网是哪个?
Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解
如何快速辨别茅台真假?关键步骤解析
如何快速生成可下载的建站源码工具?
如何在景安服务器上快速搭建个人网站?
网站建设整体流程解析,建站其实很容易!
上一篇: 简历制作网站推荐,郝文婕演的电影?
上一篇: 简历制作网站推荐,郝文婕演的电影?

