20 Как «под капотом» работает @Transactional?
Аннотация @Transactional
в Spring (и других фреймворках) используется для управления транзакциями в приложениях. Она позволяет разработчикам легко определять границы транзакций, не заботясь о низкоуровневых деталях управления транзакциями. Рассмотрим, как это работает «под капотом».
Основные аспекты работы @Transactional
:
- Прокси-объекты:
- Spring создает прокси-объект для класса, помеченного аннотацией
@Transactional
. Это может быть либо JDK-динамический прокси (если класс реализует интерфейсы), либо CGLIB-прокси (если класс не реализует интерфейсы). -
Прокси-объект перехватывает вызовы методов и добавляет логику управления транзакциями.
-
Аспектно-ориентированное программирование (AOP):
-
Spring использует AOP для внедрения поведения транзакций. При вызове метода прокси-объект сначала открывает транзакцию, затем вызывает целевой метод, и, в зависимости от результата, либо фиксирует транзакцию (commit), либо откатывает её (rollback) в случае исключения.
-
Управление транзакциями:
- Spring использует
PlatformTransactionManager
для управления транзакциями. В зависимости от конфигурации (например, JDBC, JPA, Hibernate) используется соответствующий менеджер транзакций. -
При открытии транзакции создается контекст транзакции, который отслеживает изменения и состояние.
-
Изоляция и уровень изоляции:
-
@Transactional
позволяет задавать уровень изоляции и другие параметры транзакции, такие какpropagation
,timeout
,readOnly
и т.д. Эти параметры определяют, как транзакция будет взаимодействовать с другими транзакциями. -
Обработка исключений:
- По умолчанию Spring откатывает транзакцию при возникновении непроверяемых исключений (например,
RuntimeException
). Проверяемые исключения (например,SQLException
) не приводят к откату, если не указано иное.
Пример использования:
@Service
public class UserService {
@Transactional
public void createUser(User user) {
userRepository.save(user);
// Другие операции, которые должны быть в одной транзакции
}
}
В этом примере, когда метод createUser
вызывается, Spring открывает транзакцию, выполняет сохранение пользователя и, если все проходит успешно, фиксирует транзакцию. Если возникает исключение, транзакция будет откатана.
Заключение:
Аннотация @Transactional
значительно упрощает управление транзакциями, позволяя разработчикам сосредоточиться на бизнес-логике, а не на низкоуровневых деталях работы с транзакциями.