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

在Django中正确结合Celery任务使用transaction.on_commit的方式

在Django中正确结合Celery任务使用transaction.on_commit的方式

嘿,我来帮你搞清楚这两种写法的区别,以及在你的场景下哪种才是正确的选择:

方式1:不使用transaction.atomic

def order_created(order):
    order.status = 'created'
    order.save()
    transaction.on_commit(
        partial(send_order_email.delay, order_id=order.id)
    )

方式2:使用transaction.atomic

def order_created(order):
    with transaction.atomic():
        order.status = 'created'
        order.save()
        transaction.on_commit(
            partial(send_order_email.delay, order_id=order.id)
        )

哪种正确?为什么?

答案是方式2是正确的,原因要结合你设置的ATOMIC_REQUESTS=False来理解:

当ATOMIC_REQUESTS=False时,Django不会给每个请求自动包裹事务。这时候你单独调用order.save(),它会在一个自动提交的事务中执行——也就是说save()执行完成的瞬间,数据库事务就已经提交了。

这时候再调用transaction.on_commit(),因为当前已经没有活跃的事务了,Django会立即执行你传入的Celery任务回调,这完全违背了我们用on_commit()的初衷:我们本来是想确保只有当订单状态的更新成功提交到数据库后,再触发邮件任务,避免任务执行时数据库还没同步最新数据,导致任务查不到正确的订单状态。

而方式2用transaction.atomic()显式创建了一个事务包裹住save()操作,此时save()的修改会暂时存在于这个未提交的事务中。调用transaction.on_commit()后,回调会等到这个atomic代码块结束(也就是事务成功提交)之后才执行,完美实现了“数据库更新确认后再触发异步任务”的需求。

简单总结:如果你的代码不在一个已有的事务中(比如ATOMIC_REQUESTS=False的场景),想要用transaction.on_commit()确保任务在事务提交后执行,就必须显式用transaction.atomic()包裹住你的数据库操作和on_commit()调用。

备注:内容来源于stack exchange,提问作者swaran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 14:54:34