При вызове API метод контроллера ProcessUser вызывает асинхронный метод, и API не ждет его завершения. Из этого метода я вызываю UserService для обработки пользователя.
Текущий поток:
Контроллер -> Создает поток для пользователя (с использованием метода @Async) ->
UserService (с @Transactional)
Теперь я хочу изменить логику так что если у пользователя есть несколько субпользователей, UserService должен обрабатывать все субпользователи асинхронно и параллельно для экономии времени. Однако если во время обработки любого субпользователя возникает ошибка, я хочу, чтобы вся транзакция была отменена. Пользовательский поток должен дождаться завершения всех потоков подпользователя, прежде чем завершить транзакцию.
Желаемый процесс:
Контроллер -> Создает поток для пользователя (с использованием метода @Async) ->
UserService (с @Transactional) -> Несколько потоков для параллельной
обработки (с использованием метода @Async) -> SubUserService (с @Transactional)
Валюта, с которой я столкнулся ниже. Исключение:
Вызвано: java.lang.IllegalStateException: Не найден запрос, связанный с потоком
: Вы имеете в виду атрибуты запроса вне фактического
веб-запроса или обрабатываете запрос за пределами первоначально
потока-получателя? Если вы на самом деле работаете с веб-запросом
и все равно получаете это сообщение, ваш код, вероятно, выполняется вне
DispatcherServlet: в этом случае используйте RequestContextListener или
RequestContextFilter, чтобы предоставить текущий запрос.
ПРИМЕЧАНИЕ:
- Я попробовал следующее решение, но оно не сработало:
@Bean
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public FCSessionDataBeanWebapp sessionDataBean() {
AuthenticationUser authenticationUser = null;
try{
SecurityContext securityContext = SecurityContextHolder.getContext();
OAuth2Authentication authentication = (OAuth2Authentication) securityContext.getAuthentication();
authenticationUser = (AuthenticationUser) authentication.getPrincipal();
}
catch(Exception ex){
log.error(ex.getMessage(), ex);
}
if(authenticationUser != null)
return authenticationUser.getSessionDataBeanWebapp();
else
return new FCSessionDataBeanWebapp();
} - Я использую @Transactional на уровне службы, который обрабатывает операции с базой данных, но я не использую его в методе потока или в методе потока. сам сервис потоков. Я также попытался сделать метод потока транзакционным, но это привело к ошибке «EntityManager закрыт». Поскольку для каждого потока субпользователя создается новая транзакция, для моего варианта использования она бесполезна.
- Как устранить упомянутое выше исключение «EntityManager закрыто»?
- Есть ли способ для субпользователя потоки использовать транзакцию потока родительского пользователя?
- Есть ли другой способ параллельной обработки подпользователей, при этом используя транзакцию родительского пользователя, например, с помощью
@TransactionalEventListener или других подходов?
Контроллер:
@Autowired
UserAsyncService userAsyncService;
@PostMapping("/process-user")
public ResponseEntity processUser(@RequestBody Integer userId) {
userAsyncService.processUserAsync(userId);
return ResponseEntity.ok().build();
}
UserAsyncService:
@Service
public class UserAsyncService {
@Autowired
UserService userService;
@Async("threadPoolTaskExecutor")
public void processUserAsync(Integer userId) throws Exception {
userService.processUser(userId);
}
}
Пользовательская служба:
@Service
@Transactional
public class UserService {
@Autowired
SubUserAsyncService subUserAsyncService;
public void processUser(Integer userId) throws Exception {
// process user
// done db process for user
List subUsers = userDao.retriveSubUserIds(userId);
List futures = new ArrayList();
for(Integer subUser: subusers) {
// Question : How can the following thread be implemented to use the current thread's transaction, ensuring that all subuser and parentuser data in the database is rolled back in case of an error?
CompletableFuture future = subUserAsyncService.processSubUser(subUser);
futures.add(future);
}
// Wait for all sunuser threads to complete
for (CompletableFuture future : futures) {
future.join();
}
executorService.shutdown();
}
}
SubUserAsyncService:
@Service
public class SubUserAsyncService {
@Autowired
SubUserService subUserService;
@Async("threadPoolTaskExecutor2")
public CompletableFuture processSubUserAsync(Integer userId) throws Exception {
subUserService.processUser(userId);
}
}
SubUserService:
@Transactional
@Service
public class SubUserService {
@Autowired
SubUserDao subUserDao;
public void processUser(Integer userId) throws Exception {
// process subuser
subUserDao.processUser(userId);
}
}
Подробнее здесь: https://stackoverflow.com/questions/793 ... springboot
Мобильная версия