java – CompletableFuture vs Spring Transactions
idea
I have a handler that receives a list of items and processes them asynchronously using an external web service The processing step also preserves data during processing At the end of the whole process, I want to keep the whole process with each processing result
problem
I convert each item in the list to @ R_ 404_ 248 @ and run processing tasks on them and put them back into the futures array Use it now The ofall method (sequential method) completes the future after all submitted tasks are completed, and returns another @ r containing the results_ 404_ 248@.
When I want that result, I call whenComplete(..), I want to set the returned result as data in my entity and then save it to the database, but the repository save call does nothing. It just continues to run. It will not exceed the repository save call
@Transactional public void process(List<Item> items) { List<Item> savedItems = itemRepository.save(items); final Process process = createNewProcess(); final List<@R_404_248@<ProcessData>> futures = savedItems.stream() .map(item -> @R_404_248@.supplyAsync(() -> doProcess(item,process),executor)) .collect(Collectors.toList()); sequence(futures).whenComplete((data,throwable) -> { process.setData(data); processRepository.save(process); // <-- transaction lost? log.debug("Process DONE"); // <-- never reached }); }
Sequence method
private static <T> @R_404_248@<List<T>> sequence(List<@R_404_248@<T>> futures) { @R_404_248@<Void> allDoneFuture = @R_404_248@.allOf(futures.toArray(new @R_404_248@[futures.size()])); return allDoneFuture.thenApply(v -> futures.stream().map(@R_404_248@::join).collect(Collectors.toList()) ); }
What's up? Why did the continuous call fail Is the thread that started the transaction unable to commit the transaction or missing location? All the processed data are very good, and all are very good I have tried different trading strategies, but if so, how to control which thread completes the transaction?
Any suggestions?
Solution
As mentioned above, the reason for your problem is that the transaction is closed
What you can do is create a transaction manually, providing you with comprehensive transaction control when it starts and ends
Delete @ transactional
Then in the process (..) Automatically assemble transactionmanager in:
TransactionDeFinition txDef = new DefaultTransactionDeFinition(); TransactionStatus txStatus = transactionManager.getTransaction(txDef); try { //do your stuff here like doWhateverAsync().then(transactionManager.commit(txStatus);) } catch (Exception e) { transactionManager.rollback(txStatus); throw e; }