【发布时间】:2016-06-08 07:31:44
【问题描述】:
想法
我有一个处理方法,它接收一个项目列表并使用外部 Web 服务异步处理它们。处理步骤还在处理时保留数据。在整个过程结束时,我想将整个过程与每个处理的结果一起保留。
问题
我将列表中的每个项目转换为CompletableFuture 并对它们运行处理任务,然后将它们放回期货数组中。现在使用它的.ofAll 方法(按顺序方法)在所有提交的任务完成后完成future,并返回另一个保存结果的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())
);
}
发生了什么?为什么坚持调用没有通过。启动事务的线程是否无法提交事务或者它在哪里丢失?所有处理后的数据都返回正常,一切都很好。我尝试了不同的事务策略,但是如果是这样的话,如何控制哪个线程将完成事务?
有什么建议吗?
【问题讨论】:
-
sequence方法呢,能不能展示一下? -
在期货列表上执行 allOf 只是胶水代码。
-
我对此不是 100%,但看起来
Transactional在方法启动时启动事务并在方法完成时提交,Transactional不会等待您的回调被触发。你可以用简单的线程来测试。 -
好吧,我也这么认为。如果我先做
List<ProcessData> data = sequence(futures).join()然后是repository.save(data),该方法阻塞并提交很好,我不能阻塞,但仍然需要一种方法在事务中从头到尾执行它。 -
@stjepano 你是对的 在执行开始时事务开始事务并在方法结束时提交(或如果运行时错误则回滚)。
标签: java spring multithreading hibernate transactions