Виклик Transactional методів Spring + Hibernate

Клас має два методи, обидва позначені анотацією 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 з контролера, тобто це буде єдина транзакція на усі збереження, ще не відповідає умовам задачі.

Правильне рішення

  • Прибираємо з сервісу зайвий transactional-метод збереження списку.
  • Виносимо прохід за списком з сервісу в контролер.
  • Тепер контролер буде перебирати об'єкти зі списку та викликати Transactional-метод сервиса для збереження кожного об'єкта.
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
  }
}

Desperate Housewives Susan's Art s05 e16

Desperate Housewives Susan's Art s05 e16