1. transaction.on_commit()是什麼?

這是一個回調註冊方法,在Django中用於在資料庫交易成功提交之後執行某些操作。

from django.db import transaction

transaction.on_commit(my_function)

執行這段代碼後,my_function()將在當前交易成功結束後執行。

Django transaction.on_commit 概念圖片


2. 什麼情況下使用?

情況 使用情況
希望在DB保存確定結束後執行某些操作時 ✅ 合適
希望在交易之後執行Celery任務時 ✅ 合適
外部API調用、緩存更新等 ✅ 合適
在交易外調用的順序不重要時 ❌ 不合適

3. 核心概念

  • on_commit()僅在「當前執行的交易存在時」才有意義。
  • 如果沒有交易,回調將立即執行

4. 錯誤示例

def my_view(request):
    def notify():
        print("已執行!")

    transaction.on_commit(notify)  # 由於沒有交易,立即執行!

5. 正確使用示例

from django.db import transaction

def my_view(request):
    with transaction.atomic():
        post = Post.objects.create(...)
        post.categories.add(...)

        def translate():
            translate_post.delay(post.id)

        transaction.on_commit(translate)

在上述示例中,只有在post創建和類別添加完成後,translate()才會被執行。


6. 為什麼重要?

許多開發者會混淆以下概念:

  • ORM的create()add()實際上並未提交
  • 在提交之前,所有操作均為“邏輯保存”狀態
  • Celery任務在獨立進程中執行,
  • 如果在提交之前執行,將參考不完整的數據

7. 與Celery共同使用的理想示例

@shared_task
def post_finalize_task(post_id, categories, tags):
    post = Post.objects.get(id=post_id)

    with transaction.atomic():
        for name in categories:
            cat, _ = Category.objects.get_or_create(name=name)
            post.categories.add(cat)

        for name in tags:
            tag, _ = Tag.objects.get_or_create(name=name)
            post.tags.add(tag)

        def schedule_translation():
            translate_post.delay(post.id)

        transaction.on_commit(schedule_translation)

這個結構確保了只有在類別/標籤保存確定之後才執行translate_post任務。


8. 總結

概念 介紹
何時執行? 交易成功提交之後
失敗時? rollback時絕對不執行
沒有交易時呢? 立即執行(注意!)
使用位置 with transaction.atomic()區塊內部
活用示例 執行Celery任務、發送通知、更新緩存等

9. Jesse的評論

transaction.on_commit()並不僅僅是簡單的延遲執行。
清晰表達了開發者僅在交易成功的情況下執行的意圖
是使用ORM和異步處理時必不可少的工具,以保護數據完整性。