Ответ
Вложенная транзакция (subtransaction) в Django — это точка сохранения (savepoint) внутри основной транзакции, управляемая через контекстный менеджер transaction.atomic().
Ключевое отличие: откат вложенной транзакции (например, из-за исключения) не отменяет всю родительскую транзакцию. Он лишь возвращает состояние базы данных к моменту входа во вложенный блок.
Пример:
from django.db import transaction
# Основная транзакция
with transaction.atomic():
# ... какие-то успешные операции в БД ...
try:
# Вложенная транзакция (subtransaction)
with transaction.atomic():
# Код, который может вызвать ошибку
Order.objects.create(status='invalid_data') # Пример операции
raise ValueError("Ошибка во вложенной транзакции")
except ValueError:
# Операции внутри вложенного блока 'atomic' будут отменены,
# но основная транзакция продолжится.
print("Вложенная транзакция откатилась.")
# Этот объект будет успешно сохранен, так как основная транзакция не прервалась
Product.objects.create(name='Final Product')
Основные сценарии использования:
- Изоляция части операций: Когда нужно гарантировать атомарность небольшого блока кода, не рискуя всей транзакцией при его сбое.
- Обработка данных с частичным успехом: Например, при импорте данных из файла, где ошибка в одной строке не должна отменять импорт всех предыдущих корректных строк.
Ответ 18+ 🔞
Давай разберём эту штуку, как будто я тебе на кухне объясняю, с паяльником в одной руке и пивом в другой.
Представь, что ты пишешь важный документ. Вся работа — это одна большая транзакция. Ты начал её, и всё, что ты делаешь, можно в любой момент отменить целиком, нажав Ctrl+Z до самого начала. Страшно, да? А если ты уже полдня писал?
Вот тут и появляется эта хитрая жопа — вложенная транзакция, она же subtransaction. Это как если бы ты внутри своего документа поставил временную точку сохранения. Ты пишешь какой-то рискованный абзац, который может оказаться полной хуйнёй. Если он и правда оказывается хуйнёй, ты откатываешься только до этой точки, а не на начало всего документа! Всё, что было до этого рискованного абзаца, остаётся нетронутым. Гениально, ёпта!
Вот смотри на этот код, он как раз про это:
from django.db import transaction
# Это наша основная, большая работа. Всё внутри этого блока — одна транзакция.
with transaction.atomic():
# Допустим, тут мы успешно создали пользователя, записали лог. Всё ок.
try:
# А вот тут мы ставим нашу временную точку сохранения! Вложенная транзакция.
with transaction.atomic():
# Пытаемся сделать что-то опасное. Например, создать заказ с кривыми данными.
Order.objects.create(status='invalid_data')
# И тут же, на тебе, — ошибка! Исключение!
raise ValueError("Ошибка во вложенной транзакции")
except ValueError:
# Поймали! Что происходит? Откатилось ВСЁ, что было внутри того вложенного блока `atomic`.
# Заказ с 'invalid_data' испарился, как будто его и не было.
print("Вложенная транзакция откатилась. Фух, пронесло.")
# А это — самое важное. Основная-то транзакция НЕ сломалась!
# Она жива и может продолжать работу. Этот продукт будет сохранён.
Product.objects.create(name='Final Product')
Зачем это, блядь, нужно в реальной жизни?
-
Чтобы не париться из-за мелочей. Допустим, ты обрабатываешь CSV-файл на тысячу строк. В десятой строке какая-то ерунда, которая ломает логику. Без вложенных транзакций при первой же ошибке откатится ВСЯ тысяча обработанных строк — иди всё по новой, мудак. А с ними — откатится только эта одна кривая строка, а остальные 999 уже будут в базе. Удобно, как хуй с пальто!
-
Для изоляции говнокода. У тебя есть большой и важный кусок бизнес-логики, а внутри него нужно вызвать какой-то легаси-метод от коллеги-распиздяя, который может в любой момент выстрелить в ногу. Оберни его вызов во вложенный
atomic— и если он всё-таки накроется медным тазом, твоя основная логика не пострадает. Просто скажешь "ой, ну бывает" и пойдёшь дальше.
Короче, это как страховочная верёвка при восхождении. Основная транзакция — это весь твой маршрут на гору, а вложенные — это точки страховки. Сорвался на одном сложном участке — повиснешь на последней точке, а не улетишь в хуй-knows-where к подножию. Мудро, Тургенев блядь, отдыхает.