@Транзакционный только для одного метода

#java #spring #spring-boot #transactions #spring-transactions

Вопрос:

Мне нужно создать метод @Scheduled, который содержит список схем и для каждой схемы удаляет строки из 2 таблиц.

     @Scheduled(fixedDelay = 10000)
public void scheduleFixedDelayTask() {
    List<String> presentSchemas = getPresentSchemas();
    for (String schema : presentSchemas) {
        deleteFromCustomerTables(schema);
    }
}
 

Я определил deleteFromCustomerTables как @Транзакционный(распространение = Распространение.REQUIRES_NEW), и внутри него я использую EntityManager для удаления строк из 2 таблиц.

Чтобы это сработало, мне нужно добавить @Transactional в scheduleFixedDelayTask, иначе я получу исключение TransactionRequiredException.

Моя проблема в том, что я не хочу, чтобы весь планировщик был @Транзакционным, если что-то пойдет не так в одной схеме, я не хочу выполнять откат всех схем.

Я также пробовал без @Transactional и с :

     Session session = entityManager.unwrap(Session.class);
    Transaction t = session.beginTransaction();
    //exec delete
    t.commit();
    session.close();
 

Но я все равно получаю исключение TransactionRequiredException.
У вас есть решение?

Комментарии:

1. Если вы не хотите откатывать все изменения, вы можете просто поместить транзакционный код в блок try-catch, тот, в котором произошла ошибка, завершится неудачно, и цикл будет пытаться выполнить другие, пока список не закончится.

2. даже если я определяю scheduleFixedDelayTask как @Транзакционную и помещаю try-catch вокруг deleteFromCustomerTables(схема), он все равно выполняет откат с ошибкой «Транзакция беззвучно откатана, потому что она была помечена как только для отката».

Ответ №1:

  • Вы должны быть уверены, что настроили диспетчер транзакций примерно так:
 @Configuration
@EnableTransactionManagement
public class TransactionConfig {

  @Bean
  @Primary
  public PlatformTransactionManager transactionManager() {
    return new JpaTransactionManager();
  }
}
 
  • Вы должны быть уверены, что метод deleteFromCustomerTables не находится в одном и том же компоненте, что-то вроде этого:
 @Component
class Component1 {
   void scheduleFixedDelayTask(){...}
}

@Component
class Component2 {
   void deleteFromCustomerTables(){...}
}
 
 

Но на очень высоком уровне Spring создает прокси-серверы для классов, которые
объявляют @Transactional в самом классе или в его членах. Прокси
-сервер в основном невидим во время выполнения. Это позволяет Spring вводить
поведение до, после или вокруг вызовов методов в
проксируемый объект. Управление транзакциями-это всего лишь один пример поведения
, к которому можно подключиться. Проверки безопасности — это другое. И вы также можете
предоставить свои собственные для таких вещей, как ведение журнала. Поэтому, когда вы аннотируете
метод с помощью @Transactional, Spring динамически создает прокси-сервер, который
реализует тот же интерфейс(ы), что и класс, который вы аннотируете. И
когда клиенты совершают вызовы в ваш объект, вызовы перехватываются
, а поведение вводится через механизм прокси-сервера.

Комментарии:

1. Большое спасибо! Моя проблема заключалась в использовании одного и того же компонента! Создание второго компонента решило проблему.