子线程抛出异常和主线程事务回滚

本文主要记录多线程运用时子线程返回结果、子线程异常事务回滚、子线程异常主线程事务回滚
本文只是学习记录,无太多论述性的观点,有误敬请指正

业务场景

如果子线程的发生异常,主线程回滚,否则提交


解决方案

既然说到线程,那么就是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);
    }


}

发布了86 篇原创文章 · 获赞 110 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/libra_ts/article/details/85165743
今日推荐