You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django+Postgres如何原子实现用户维度计数器自增并赋值给新建条目

方案1:UPDATE配合RETURNING直接获取自增后的值(最优,性能最高)

PostgreSQL原生支持UPDATE语句的RETURNING子句,可以在更新用户计数器的同时直接返回更新后的值,全程仅1次数据库交互,天然原子,无并发冲突,是性能最优的方案。

Django 4.1及以上版本可以直接用ORM实现:

from django.db import models
from django.contrib.auth import get_user_model

User = get_user_model()

def create_item(user_id, name):
    # 自增计数器同时返回更新后的值
    new_counter = User.objects.filter(id=user_id).annotate(
        new_counter=models.F('item_counter') + 1
    ).update(
        item_counter=models.F('new_counter'),
        returning=('new_counter',)
    )[0][0]
    # 用返回值创建Item记录
    return Item.objects.create(name=name, user_id=user_id, item_num=new_counter)

如果使用Django 4.1以下版本,可以直接执行原生SQL实现完全一致的效果:

from django.db import connection

def create_item(user_id, name):
    with connection.cursor() as cursor:
        cursor.execute("""
            UPDATE auth_user 
            SET item_counter = item_counter + 1 
            WHERE id = %s 
            RETURNING item_counter
        """, [user_id])
        new_counter = cursor.fetchone()[0]
    return Item.objects.create(name=name, user_id=user_id, item_num=new_counter)

方案2:显式事务加行锁(兼容性最好)

如果需要兼容更多场景,可以用事务加行锁的方式实现,逻辑更直观:

from django.db import transaction

@transaction.atomic
def create_item(user_id, name):
    # 锁定对应用户行,事务结束前其他请求无法修改该行
    user = User.objects.select_for_update().get(id=user_id)
    user.item_counter += 1
    user.save(update_fields=['item_counter'])
    # 创建Item记录
    return Item.objects.create(
        name=name,
        user=user,
        item_num=user.item_counter
    )

该方案需要2次数据库交互,性能略低于方案1,但不需要依赖高版本Django特性,代码可读性更强。


注意事项

  • 禁止先在Python层查询计数器值再自增更新,这种写法在并发场景下会出现竞态条件,导致多个条目拿到相同的item_num
  • 两种方案都天然支持多用户独立计数,更新仅针对单用户行加锁/操作,不同用户的创建请求不会互相阻塞

内容的提问来源于stack exchange,提问作者user3599803

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 05:06:00