1. transaction.on_commit()
이란?
Django에서 데이터베이스 트랜잭션이 성공적으로 커밋된 직후 어떤 작업을 실행하고 싶을 때 사용하는 콜백 등록 메서드입니다.
from django.db import transaction
transaction.on_commit(my_function)
이 코드를 실행하면, 현재 트랜잭션이 성공적으로 끝난 이후에 my_function()
이 실행됩니다.
2. 어떤 상황에서 사용하는가?
상황 | 사용 여부 |
---|---|
DB에 저장이 확실히 끝난 후 무언가 실행하고 싶을 때 | ✅ 적합 |
Celery task를 트랜잭션 이후에 실행하고 싶을 때 | ✅ 적합 |
외부 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 task는 별도 프로세스에서 실행되므로,
- 커밋 전에 실행되면 불완전한 데이터를 참조하게 됨
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
task를 실행하도록 보장합니다.
8. 요약 정리
개념 | 설명 |
---|---|
언제 실행됨? | 트랜잭션이 성공적으로 커밋된 직후 |
실패 시? | rollback되면 절대 실행되지 않음 |
트랜잭션 없으면? | 즉시 실행됨 (주의!) |
사용 위치 | with transaction.atomic() 블록 내부 |
활용 예시 | Celery task 실행, 알림 발송, 캐시 반영 등 |
9. Jesse의 코멘트
transaction.on_commit()
은 단순한 지연 실행이 아닙니다.
트랜잭션이 성공한 경우에만 실행하겠다는 개발자의 명확한 의도 표현이며,
ORM과 비동기 처리를 함께 사용할 때, 데이터 무결성을 지키기 위한 필수 도구입니다.
Add a New Comment