Когда вы аннотируете класс как @Transactional
, как в вашем примере, вы определяете в каждом методе класса границу транзакции.
В вашем примере аннотация будет применяться к runPendingTasks
method.
Вы не можете разместить аннотацию @Transactional
в частных методах (связанных с тем, что предлагает @crizzis), это не влияет на них.
Вся эта информация объясняет, почему появляются предупреждения в журналах: у вас есть одна транзакция, инициированная runPendingTasks
, и в ней несколько потоков, обрабатывающих метод doTask
. Вызов метода runPendingTasks
заканчивается, но эти потоки все еще живы.
Один из подходов к решению проблемы может заключаться в завершении sh всех задач, связанных с базой данных, в границах транзакции.
Здесь , в Stackoverflow, у вас есть поток, который показывает вам, как вы можете завершить sh список задач асинхронно.
Я рекомендую вам прочитать некоторые статьи из блога Томаша Нуркевича , он даст вам - по крайней мере, для меня - отличное понимание асинхронных вычислений и Java параллелизма в целом.
Следуя его совету , вы можете определить свой код следующим образом:
@RequestScoped
@Transactional(REQUIRED)
public class TaskService {
@Inject
ManagedExecutor executor;
public void runPendingTasks() {
final List<Task> taskList = Task.list("pending=?1 ",true);
logger.debug("Found " + taskList.size() + " tasks pending ");
final List<CompletableFuture<boolean>> futures = taskList.stream().
map(task -> CompletableFuture.supplyAsync(() -> doTask(task), executor)).
collect(Collectors.<CompletableFuture<boolean>>toList())
;
final CompletableFuture<Void> allDoneFuture =
CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
final CompletableFuture<List<boolean>> allDone = allDoneFuture.thenApply(v ->
futures.stream().
map(future -> future.join()).
collect(Collectors.<boolean>toList())
);
final boolean result = allDone.thenAccept(results ->
results.stream().
reduce((a, b) -> a || b)
);
}
private boolean doTask(final Task task) {
logger.debug("Going to run task " + task.getId() );
//Do some DB updation here
return true;
}
}