@Transactional
@Transactional — одна аннотация, которая оборачивает метод в транзакцию базы данных (см. тему «Транзакции, ACID, уровни изоляции»), без ручного BEGIN/COMMIT/ROLLBACK.
@Service
class OrderService {
@Transactional
void createOrder(Order order) {
orderRepository.save(order);
inventoryService.decreaseStock(order); // если упадёт — откатится и save() выше
paymentService.charge(order);
}
}
Если любая строка внутри метода бросит исключение — все изменения откатятся, как будто метод не выполнялся вообще. Если метод завершился без ошибок — транзакция автоматически коммитится.
Копнуть глубже
По умолчанию @Transactional откатывается только на RuntimeException, не на проверяемые (checked) исключения (см. тему «checked vs unchecked»). Если нужно откатить и на checked-исключение тоже:
@Transactional(rollbackFor = Exception.class)
void createOrder(Order order) throws CustomCheckedException { ... }
@Transactional — это тоже Proxy (см. тему «Как работают прокси»), как и @Cacheable — Spring оборачивает бин прокси-объектом, который открывает транзакцию до вызова реального метода и коммитит/откатывает после. Поэтому, как и с @Cacheable, вызов метода с @Transactional изнутри того же класса (this.createOrder()) не пройдёт через прокси — аннотация не сработает.
Read-only оптимизация для методов, которые только читают данные:
@Transactional(readOnly = true)
List<Order> getOrders() { ... }
Это подсказка базе данных не тратить ресурсы на отслеживание изменений — небольшой, но реальный прирост производительности на read-операциях.
• почему `@Transactional` не сработает при вызове метода внутри того же класса (если дошёл до 2-го слоя).