观
我有一个处理方法,它接收一个项目列表并使用外部Web服务异步处理它们。处理步骤还会在处理时保留数据。在整个过程结束时,我希望将整个过程与每个处理结果一起保持。
问题
我将列表中的每个项目转换为CompletableFuture
并对它们运行处理任务,然后将它们放回到期货数组中。现在使用其.ofAll
方法(按顺序方法)完成所有提交任务完成后的未来,并返回保存结果的另一个CompletableFuture
。
当我想得到那个结果时,我调用.whenComplete(..)
,并希望将返回的结果作为数据设置到我的实体中,然后保存到数据库,但是存储库保存调用不执行任何操作并继续线程只是继续运行,它不会超过存储库保存调用。
@Transactional
public void process(List<Item> items) {
List<Item> savedItems = itemRepository.save(items);
final Process process = createNewProcess();
final List<CompletableFuture<ProcessData>> futures = savedItems.stream()
.map(item -> CompletableFuture.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
});
}
序列方法
private static <T> CompletableFuture<List<T>> sequence(List<CompletableFuture<T>> futures) {
CompletableFuture<Void> allDoneFuture =
CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
return allDoneFuture.thenApply(v ->
futures.stream().map(CompletableFuture::join).collect(Collectors.toList())
);
}
发生了什么事?为什么持续的呼叫没有通过。启动事务的线程是否无法提交事务或丢失的位置?所有处理过的数据都很好,并且都很好。我尝试过不同的交易策略,但如果是这样的话,如何控制哪个线程完成交易呢?
有什么建议吗?
答案 0 :(得分:5)
如上所述,您遇到问题的原因是交易结束 当达到方法进程(..)的返回时。
您可以做的是手动创建交易,为您提供全面的交易 控制它何时开始和结束。
删除@Transactional
然后在进程(..)中自动装配TransactionManager:
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;
}
答案 1 :(得分:2)
如果是Spring Boot Application,则需要进行以下配置。
主应用程序方法应使用@EnableAsync注释。
@Async注释应位于具有@Transactional注释的方法的顶部。这是必要的,表明将在子线程中进行处理。