У класса есть два метода, оба помеченные аннотацией Transactional, что происходит, когда один из этих методов вызывает второй метод?
public class MyServiceImpl {
@Transactional
public void method1() {
//do something
method2();
}
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void method2() {
//do something
}
}
«В связи с тем, что для поддержки транзакций через аннотации используется Spring AOP, в момент вызова method1() на самом деле вызывается метод прокси объекта. Создается новая транзакция и далее происходит вызов method1() класса y ServiceImpl. А когда из method1() вызовем method2(), обращения к прокси нет, вызывается уже сразу метод нашего класса и, соответственно, никаких новых транзакций создаваться не будет».
Источник: https://habr.com/ru/post/347752/
Рассмотрим живой пример, когда может возникнуть подобная ошибка
- Есть контроллер, который получать из некого источника список объектов, которые необходимо сохранить в БД
- Есть сервис, который при помощи DAO сохраняет объекты
- Задача: сохранение каждого отдельного объекта должно производиться в отдельной транзакции
Неправильное решение
public class EntityService {
//...
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void persistEntity(Entity entity) {
entityDao.persist(entity);
}
@Transactional
public void persistEntityList(List<Entity> entityList) {
for(Entity enity : entityList) persistEntity(enity);
}
}
public class EntityController() {
public void persistAll() {
//...
entityService.persistEntityList(entityList);
}
}
В данном случае, будет создана лишь одна транзакция - при вызове метода сервиса persistEntityList из контроллера, то есть это будет единственная транзакция на все сохранения, что является ошибкой.
Правильное решение
- Убираем лишний транзакционный метод сохранения списка из сервиса
- Выносим проход по списку из сервиса в контроллер
- Теперь контроллер будет перебирать объекты из списка и вызывать транзакционный метод сервиса для сохранения
public class EntityService {
//...
@Transactional
public void persistEntity(Entity entity) {
entityDao.persist(entity);
}
}
public class EntityController() {
public void persistAll() {
//...
for(Entity enity : entityList) entityService.persistEntity(enity);
// or: entityList.forEach(entityService::persist); // Java 8 style
}
}
No comments:
Post a Comment