10. Обеспечить создание транзакции при внутреннем вызове через self-inject
Условие задачи:
Дан Spring-сервис с двумя методами: a() и b().
Метод a() помечен @Transactional, а из метода b() выполняется внутренний вызов a().
Необходимо определить, сколько транзакций будет создано при внешнем вызове b(), и исправить код с помощью self-injection так, чтобы a() вызывался через Spring-прокси.
Код:
@Service
class SomeService {
@Transactional
public void a() {
}
public void b() {
a();
}
}
Вызов:
someService.b();
Спойлеры к решению
Подсказки
b() не помечен @Transactional.💡 Вызов
a() внутри того же объекта является self-invocation.💡 Такой вызов не проходит через Spring-прокси.
💡 Нужно получить прокси текущего сервиса и вызвать
a() через него.💡 При self-injection удобно использовать
@Lazy, чтобы избежать циклической зависимости при создании бина.Решение
При обычном вызове:
someService.b();
будет создано 0 транзакций.
Метод b() сам не является транзакционным, а вызов:
a();
фактически выполняется как:
this.a();
Он не проходит через Spring-прокси, поэтому @Transactional на a() не срабатывает.
Вариант с self-injection:
@Service
public class SomeService {
private final SomeService self;
public SomeService(
@Lazy SomeService self
) {
this.self = self;
}
@Transactional
public void a() {
// работа в транзакции
}
public void b() {
self.a();
}
}
Теперь вызов:
self.a();
проходит через Spring-прокси. Аннотация @Transactional перехватывается транзакционным interceptor, и для метода a() создаётся транзакция.
В результате при вызове:
someService.b();
будет создана 1 транзакция — для метода a().