Django悲观锁怎么用_select_for_update()在事务中锁定行记录

张开发
2026/4/9 4:29:25 15 分钟阅读

分享文章

Django悲观锁怎么用_select_for_update()在事务中锁定行记录
必须在数据库事务中使用select_for_update()来避免“读-改-写”竞态否则锁无效需确保查询走索引以防升级为表锁并合理配置nowait、skip_locked、of等参数。什么时候必须用 select_for_update() 而不是普通查询当多个并发请求可能同时读取同一行、再基于该行数据做修改比如扣库存、生成唯一订单号、递增计数器且你要求「读到的值在后续更新时仍有效」就必须上悲观锁。普通 get() 或 filter() 不加锁读完就释放中间可能被别人改掉 —— 这就是典型的「读-改-写」竞态。常见错误现象IntegrityError: duplicate key value violates unique constraint比如抢购时生成重复订单号或库存扣成负数。必须在数据库事务中调用否则 Django 会静默忽略锁不报错但没效果只对支持行级锁的数据库生效PostgreSQL、MySQL InnoDBSQLite 不支持锁的是查询结果集里的行不是整个表但如果 filter() 条件没走索引可能升级为表锁MySQL 尤其危险select_for_update() 的参数怎么选nowait、skip_locked、of默认行为是阻塞等待锁释放但线上服务通常不能卡住请求。关键参数要按场景配nowaitTrue拿不到锁立刻抛 DatabaseErrorPostgreSQL或 OperationalErrorMySQL适合快速失败重试skip_lockedTrue跳过已被锁的行只锁能拿到的行MySQL 8.0/PostgreSQL 9.5适合批量处理队列任务of[field_name]只锁指定字段所在的行需配合 select_related() 或明确主表避免锁扩散到关联表示例Order.objects.select_for_update(nowaitTrue).get(id123)比无参数更可控。 Evoker 一站式AI创作平台

更多文章