Всем привет, в ближайшее время планирую уделить внимание Spring, публиковать жизненный цикл бинов думаю не имеет смысла, так как это достаточно заезженная тема, поэтому сегодня сразу дальше)
Почему @Transactional иногда НЕ работает?
Представим обычный сервис:
@Service
public class OrderService {
@Transactional
public void createOrder() {
saveOrder();
}
@Transactional(propagation = REQUIRES_NEW)
public void saveOrder() {
// отдельная транзакция
}
}
Кажется, что saveOrder() запустится в новой транзакции.
Но нет. 😈Если вызвать:
createOrder();
то saveOrder() вызывается напрямую через this.
А Spring работает немного иначе.
Когда контейнер создаёт Bean, вокруг него может появиться Proxy:
OrderService
↑
│
Spring Proxy
│
└── @Transactional
Вызов извне:
orderService.createOrder();
проходит через Proxy:
Controller
↓
Proxy
↓
Transaction
↓
OrderService
А вот внутри самого объекта:
this.saveOrder();
Proxy уже не участвует:
OrderService
↓
this.saveOrder()
Поэтому Spring не видит этот вызов и не может применить к нему REQUIRES_NEW.
И вот здесь часто возникает вопрос на собеседовании:
Почему @Transactional стоит на методе, но транзакция не создаётся
?Ответ:
Аннотация сама по себе ничего не перехватывает.
Spring использует AOP и Proxy, а значит вызов должен пройти через Proxy.
Поэтому такой код:
this.saveOrder();
может вести себя совсем не так, как ожидает разработчик.
Главная мысль:
Когда видите @Transactional, думайте не только про транзакцию.
Думайте:
Bean → Proxy → AOP → вызов метода.
И тогда половина «магии Spring» становится обычной механикой. 😉