Что такое паттерн Unit of Work?
Unit of Work (Единица работы) – паттерн, который отслеживает все изменения доменных объектов в рамках одной бизнес-операции и выполняет их в БД как единую атомарную транзакцию. Как корзина покупок в магазине: вы складываете товары, убираете ненужные, а на кассе всё оформляется одной операцией.
Пример
┌────────────────────────────────────────────┐
│ Unit of Work │
│ │
│ Новые: [Payment A] │
│ Изменённые: [Account X, Account Y] │
│ Удалённые: [] │
│ │
│ commit() → INSERT Payment A │
│ UPDATE Account X │
│ UPDATE Account Y │
│ COMMIT │
└────────────────────────────────────────────┘
Зачем нужен
- Группировка нескольких операций в одну транзакцию.
- Минимизация обращений к БД (batch insert/update).
- Гарантия целостности данных – либо все изменения применяются, либо ни одно.
- Отслеживание изменений (dirty checking).
Реализация в Java/Spring через JPA/Hibernate
В Java-экосистеме Unit of Work реализуется неявно через JPA/Hibernate. Persistence Context в JPA – это и есть реализация паттерна Unit of Work:
Пример кода
@Service
public class TransferService {
@Transactional // Spring начинает Unit of Work
public void transfer(Long fromId, Long toId, BigDecimal amount) {
Account from = accountRepository.findById(fromId).orElseThrow();
Account to = accountRepository.findById(toId).orElseThrow();
from.withdraw(amount); // Hibernate отслеживает изменение (dirty)
to.deposit(amount); // Hibernate отслеживает изменение (dirty)
// НЕ нужно вызывать save() -- Hibernate при commit()
// автоматически выполнит UPDATE для всех "грязных" сущностей
}
// По завершении метода Spring коммитит транзакцию
// Hibernate выполняет flush() -- записывает все изменения в БД
}
Как работает в Hibernate
@Transactionalначинает транзакцию и создаёт Persistence Context.- Загруженные сущности отслеживаются (managed state).
- Изменения сущностей запоминаются в Persistence Context.
- При коммите (
flush()) Hibernate сравнивает текущее состояние с исходным (dirty checking) и генерирует SQL. - Все SQL выполняются в рамках одной транзакции.
Итог
Persistence Context в JPA – это реализация Unit of Work. Разработчику на Spring Boot редко приходится реализовывать этот паттерн вручную, но понимание его механики помогает избежать типичных ошибок: например, модификация detached-сущности не будет автоматически сохранена, потому что она находится вне Unit of Work.
На собеседовании: Интервьюер ожидает связь Unit of Work с Hibernate Persistence Context и
@Transactional. Частая ошибка – не знать, что dirty checking происходит автоматически, и вызыватьsave()для каждой managed-сущности.