#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. Большое спасибо! Моя проблема заключалась в использовании одного и того же компонента! Создание второго компонента решило проблему.