主线程上有@Transactional注解,并且调用了异步方法,在异步方法执行过程中遇到数据库连接异常,因为异步线程发生的异常,主线程无法捕获,所以未进行事务回滚。
关于线程的两个接口Callable与Runnable之间的区别:
Callable.call()接口相较于Runnable.run(),是带有返回值并抛出异常,所以想捕获子线程的异常可以通过Callable接口进行实现。
public static final <T> T submit(Callable<T> task, long timeout) {
CustomFutureTask<T> future = (CustomFutureTask<T>) executor.submit(task);
try {
return (T) future.get(timeout, TimeUnit.MILLISECONDS);
} catch (Exception e) {
try {
future.cancel(true);
} catch (Exception ex) {
/* ignore */
}
throw new TaskException(e.getMessage());
}
}
对于线程池来说,ThreadPoolTaskExecutor有两种执行线程任务的方法:execute()和submit()。
execute()没有返回值,所以无法判断任务是否成功完成,对应的线程类实现Runnable接口。
submit()有返回值,返回一个Future,对应的线程类实现Callable接口。Future.get()可以阻塞主线程,从而判断子线程任务的执行结果,且可以抛出异常。