Ответ
Unit of Work — это поведенческий паттерн проектирования, который отслеживает изменения бизнес-объектов и координирует их запись в базу данных в рамках одной транзакции. Его главная цель — обеспечить атомарность и согласованность данных при выполнении группы операций.
Паттерн решает проблему выполнения нескольких действий (вставка, обновление, удаление) как единого целого. Все изменения накапливаются и применяются к базе данных одним вызовом (commit), либо полностью отменяются (rollback) в случае ошибки.
Ключевые задачи:
- Отслеживание состояния: Регистрирует новые, измененные и удаленные объекты.
- Группировка операций: Объединяет все изменения в одну транзакцию.
- Атомарность: Гарантирует, что либо все изменения будут сохранены, либо ни одно из них.
Многие ORM, например SQLAlchemy, реализуют этот паттерн через объект сессии (Session). Вот пример явной реализации с использованием контекстного менеджера в Python:
# Пример реализации паттерна Unit of Work
class UnitOfWork:
def __init__(self, session_factory):
self.session_factory = session_factory
def __enter__(self):
# В начале блока with создается новая сессия
self.session = self.session_factory()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
# При выходе из блока with
if exc_type:
# Если произошло исключение, откатываем транзакцию
self.session.rollback()
else:
# Иначе — успешно коммитим
self.session.commit()
self.session.close()
# Использование в сервисном слое
# Session - это сконфигурированная фабрика сессий SQLAlchemy
with UnitOfWork(Session) as uow:
user = User(name='Alice')
uow.session.add(user)
# commit или rollback произойдет автоматически при выходе из блока Ответ 18+ 🔞
А, ну это ж классика, блядь! Unit of Work, ёпта! Это когда ты, сука, как на рынке, набрал в корзину всякой хуйни — помидоров, огурцов, яблок, а потом подходишь к кассе и одним махом, блядь, всё оплачиваешь. Или, если денег не хватило, такой: «Ой, бля, извините», — и вываливаешь всё обратно на прилавок. Вот и весь паттерн, в рот меня чих-пых!
Суть-то в чём, а? Чтобы не бегать к базе данных на каждый чих: «О, добавил запись!», «О, обновил!», «О, удалил!». Это ж заебёшься, блядь, и базу заебёшь. А тут ты копишь изменения в своей оперативке, как хитрая жопа, а потом — раз! — и отправляешь одним здоровенным пакетом. Либо всё сработает, либо, если где-то косяк, нихуя не сработает. Атомарность, блядь, называется. Всё или ничего. Красота!
Вот смотри, как это в коде выглядит, если самому, на коленке, собрать:
# Пример реализации паттерна Unit of Work
class UnitOfWork:
def __init__(self, session_factory):
self.session_factory = session_factory
def __enter__(self):
# В начале блока with создается новая сессия
self.session = self.session_factory()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
# При выходе из блока with
if exc_type:
# Если произошло исключение, откатываем транзакцию
self.session.rollback()
else:
# Иначе — успешно коммитим
self.session.commit()
self.session.close()
# Использование в сервисном слое
# Session - это сконфигурированная фабрика сессий SQLAlchemy
with UnitOfWork(Session) as uow:
user = User(name='Alice')
uow.session.add(user)
# commit или rollback произойдет автоматически при выходе из блока
Видишь эту магию? Зашёл в блок with — сессия открылась. Надобавлял туда, наобновлял, наудалял. А как выходишь — оно само смотрит: «Так, чувак, тут всё чисто? Не упало ничего?». Если чисто — коммит, блядь! Если где-то посередине вылетело исключение — роллбэк, и все твои изменения, как корова языком слизала. Ни хуя не осталось. Порядок, а не жизнь!
А в нормальных ORM, типа SQLAlchemy, это вообще из коробки есть. Там этот Session и есть твой Unit of Work, готовый, обкатанный. Но понимать, как эта штука изнутри работает — это, блядь, сила. Чтобы не быть тем самым распиздяем, который в каждом углу свою сессию плодит, а потом охуевает, почему данные не консистентные.