1. Was ist transaction.on_commit()
?
Es handelt sich um eine Callback-Registrierungsmethode, die in Django verwendet wird, wenn man nach erfolgreichem Commit einer Datenbanktransaktion eine Aktion ausführen möchte.
from django.db import transaction
transaction.on_commit(my_function)
Wenn dieser Code ausgeführt wird, wird my_function()
nach erfolgreichem Abschluss der aktuellen Transaktion ausgeführt.
2. In welchen Situationen wird es verwendet?
Situation | Verwendung |
---|---|
Wenn man nach dem sicheren Speichern in die DB etwas ausführen möchte | ✅ Geeignet |
Wenn man Celery-Tasks nach der Transaktion ausführen möchte | ✅ Geeignet |
Für externe API-Calls, Cache-Aktualisierungen usw. | ✅ Geeignet |
Wenn die Reihenfolge der Aufrufe außerhalb der Transaktion nicht wichtig ist | ❌ Nicht geeignet |
3. Kernkonzepte
on_commit()
hat nur Bedeutung, wenn eine aktuelle Transaktion aktiv ist.- Wenn keine Transaktion vorhanden ist, wird der Callback sofort ausgeführt!
4. Falsches Beispiel
def my_view(request):
def notify():
print("Ausgeführt!")
transaction.on_commit(notify) # Da keine Transaktion vorhanden ist, wird es sofort ausgeführt!
5. Richtiges Beispiel
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)
In diesem Beispiel wird translate()
nur ausgeführt, nachdem post
erstellt und die Kategorien hinzugefügt wurden.
6. Warum ist das wichtig?
Viele Entwickler verwechseln folgendes:
- ORMs
create()
,add()
sind nicht tatsächlich committed - Vor dem Commit befinden sich alle in "logischer Speicherung" Status
- Celery-Tasks werden in separaten Prozessen ausgeführt,
- Wenn sie vor dem Commit ausgeführt werden, wird auf unvollständige Daten verwiesen
7. Ideales Beispiel mit 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)
Diese Struktur stellt sicher, dass die Speicherung von Kategorien/Tags abgeschlossen ist, bevor der translate_post
Task ausgeführt wird.
8. Zusammenfassung
Konzept | Beschreibung |
---|---|
Wann wird es ausgeführt? | Unmittelbar nach erfolgreichem Commit der Transaktion |
Im Falle eines Fehlers? | Wird niemals ausgeführt, wenn ein Rollback passiert |
Wenn keine Transaktion vorhanden ist? | Wird sofort ausgeführt (Vorsicht!) |
Verwendungsort | Innerhalb des with transaction.atomic() Blocks |
Anwendungsbeispiele | Ausführung von Celery-Tasks, Benachrichtigungen, Cache-Updates usw. |
9. Jesses Kommentar
transaction.on_commit()
ist nicht einfach nur eine Verzögerung der Ausführung.
Es ist ein klares Ausdruck der Absicht des Entwicklers, dass es nur ausgeführt wird, wenn die Transaktion erfolgreich ist, und es ist ein notwendiges Werkzeug, um die Datenintegrität zu wahren, wenn ORM und asynchrone Verarbeitung zusammen verwendet werden.
Add a New Comment