@Transactional и self-invocation в SpringВы знали, что вызов метода с
@Transactional внутри того же класса не активирует транзакцию? Это один из самых частых подводных камней.📌 Почему так происходит?
Spring AOP работает через прокси. Когда вы вызываете метод
this.someTransactionalMethod(), вы обходите прокси и вызываете метод напрямую — без обёртки, которая включает транзакцию.Пример:
@Service
public class UserService {
public void createUser() {
// транзакция не начнётся
this.saveUser();
}
@Transactional
public void saveUser() {
// ожидаем, что тут будет транзакция, но её нет
}
}
⚠️ Итог: никакой транзакции, и вы получите баг, который сложно заметить: данные не откатываются, lazy-loading кидает
LazyInitializationException, и т.д.💡 Как правильно:
1. Вынести transactional-метод в другой бин:
@Service
public class UserSaver {
@Transactional
public void saveUser() { ... }
}
2. Или получить прокси текущего бина через
AopContext:
public void createUser() {
((UserService) AopContext.currentProxy()).saveUser();
}
📌 Для второго варианта не забудьте включить:
@EnableAspectJAutoProxy(exposeProxy = true)
⚠️ Важно: Не используйте
AopContext без крайней необходимости. Предпочтительнее делегировать логику в отдельный бин — это чище и легче тестируется.👉@BookJava
