本文主要记录多线程运用时子线程返回结果、子线程异常事务回滚、子线程异常主线程事务回滚
本文只是学习记录,无太多论述性的观点,有误敬请指正
业务场景
如果子线程的发生异常,主线程回滚,否则提交
解决方案
既然说到线程,那么就是Runnable、Thread、Callable三种方式 Runnable、Thread没有返回值、也无法抛出异常,即使抛出异常,主线程也无法捕获。所以就采用Callable的方式Callable可采用返回值判断和异常抛出
@Override
@Transactional
public boolean testTransaction(String key) {
List<GpOut> gpOuts = gpOutDao.selectByKeySelective(null);
List<GpOut> list = new ArrayList<>();
for (GpOut gpOut : gpOuts) {
if (list.size() == 3) {
list.add(gpOut);
Future<String> future = taskExecutor.submit(new MyCallable(gpOutDao, list));
try {
String childThreadResult = future.get();
if ("failed".equals(childThreadResult)) {
//throw new RuntimeException("子线程异常"); //如果采用返回值方式则此处抛出异常,主线程回滚
}
} catch (Exception e) {
throw new RuntimeException(e);//此处则是子线程抛出的异常,主线程回滚
}
list.clear();//清除前一批次
} else {
list.add(gpOut);
}
}
//主线程更新操作
return true;
}
//子线程内部类,主线程给子线程传参可采用这种构造方式传参
class MyCallable implements Callable<String> {
private GpOutDao gpOutDao;
List<GpOut> list;
public MyCallable(GpOutDao gpOutDao, List<GpOut> list) {
this.gpOutDao = gpOutDao;
this.list = list;
}
@Override
public String call() throws Exception {
try{
//处理子线程业务耗时操作
return "success";
}catch(Exception e){
return "failed";
//throw new RuntimeException(e); //采用异常方式可抛出异常
}
}
}
当批次里面有多次数据库操作,那么如果子线程的发生异常,子线程也需要事务回滚
此处可采用编程式事务
public String call() throws Exception {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
PlatformTransactionManager txManager = SpringUtil.getBean(PlatformTransactionManager.class);
TransactionStatus status = txManager.getTransaction(def);
try {
//运行业务操作
txManager.commit(status); // 提交事务
} catch (Exception e) {
txManager.rollback(status); // 回滚事务
throw new RuntimeException(e);
}
return "success";
}
SpringUtil
package com.morning.star.pt.admin.component;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
// 非@import显式注入,@Component是必须的,且该类必须与main同包或子包
// 若非同包或子包,则需手动import 注入,有没有@Component都一样
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if(SpringUtil.applicationContext == null){
SpringUtil.applicationContext = applicationContext;
}
}
//获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过class获取Bean.
public static <T> T getBean(Class<T> clazz){
return getApplicationContext().getBean(clazz);
}
}