Springboot和Transcation事务管理

Springboot的@Transactional 注解实现数据库事务处理

一、注解式事务
1、启动类

添加@EnableTransactionManagement开启事务

2、业务类添加注解
  • @Transactional 数据库事务注解
    • propagation 事务传播行为配置
      • REQUIRED(0) 如果当前已经有事务则使用该事务,如果没有则新建一个事务
      • SUPPORTS(1) 如果当前有事务则使用当前事务,如果没有则无事务
      • MANDATORY(2) 如果当前有事务则使用当前事务,如果没有则报错
      • REQUIRES_NEW(3) 如果当前已经有事务则挂起当前事务另建一个事务,如果没有事务则新建一个事务
      • NOT_SUPPORTED(4) 即当前方法必须不在事务中,如果当前有事务则挂起
      • NEVER(5) 当前方法不应该在事务中运行,如果有,就抛异常
      • NESTED(6) 如果当前有事务运行,则再这个事务中嵌套运行(即外部事务回滚会导致内部事务回滚,内部事务回滚则不会影响外部事务),如果没有事务则另起一个事务,并在事务中运行
    • isolation 事务的隔离级别,事务的隔离级别默认是跟随数据库的事务隔离级别
      • DEFAULT 默认级别,默认跟随数据库的隔离级别
      • READ_UNCOMMITTED 读未提交
      • READ_COMMITTED 读已提交
      • REPEATABLE_READ 可重复读(mysql默认级别)
      • SERIALIZABLE 串行化
    • timeout 事务超时设置,默认是30秒
    • readOnly 设置事务为只读事务,true为只读,false为可读写,默认为false
      • true 只读
      • false 可读写,默认为可读写
    • rollbackFor/rollbackForClassName 回滚异常类
    • noRollbackFor/noRollbackForClassName 不会滚异常类
    • value/transactionManager 指定事务管理器
      • PlatformTransactionManager 事务管理器接口
      • DataSourceTransactionManager 但数据源事务管理器
      • JtaTransactionManager JTA事务管理器
      • HibernateTransactionManager Hibernate框架事务管理器
// 使用较为简单
@Service
@Transactional(readOnly = true,rollbackFor = {RuntimeException.class,BizException.class})
public class UserService {
    
	//标注在方法上,作为类内部方法局部
    @Transactional(readOnly = false,rollbackFor = Exception.class)
    public Integer updates(User blues,User zhangsan) throws Exception{
       // ... do somethings
    }
}
3、事务传播行为介绍
(1) Propagation.REQUIRED
  • Spring默认传播行为是reuqired
  • 当前有事务,使用当前事务
  • 当前没有事务,创建新事物,即保证当前方法在事务中
(2)Propagation.REQUIRES_NEW
  • 当前没有事务,创建事务运行
  • 当前有事务,创建新事物,即存在两个独立的事务
  • 不管当前方法是否有事务,都会创建一个新事物,即存在两个独立事务
(3)Propagation.SUPPORTED
  • 当前有事务时,使用当前事务,
  • 当前没有事务时,无事务运行
(4)Propagation.NOT_SUPPORTS
  • 当前存在事务,则挂起事务,无事务运行
  • 当前不存在事务,直接运行
  • 即当前方法不支持事务
(4)Propagation.MANDATORY
  • 当前存在事务,使用当前事务运行
  • 当前不存在事务,抛出异常
  • 即当前传播中必须有事务
(5)Propagation.NEVER
  • 当前有事务,则抛异常
  • 当前没有事务,正常运行
(7)Propagation.NEWSTED
  • 当前有事务,在当前事务下创建一个嵌套事务,外层事务异常,内外层事务都回滚,内存事务异常,则只回滚内存事务,外层事务不会回滚
  • 当前没有事务,则创建一个事务
二、@Transcation注解事务不生效场景
1、不生效场景总览
  1. 数据库引擎不支持事务
    • mysql的ISAM不支持事务
  2. 注解的类是非public修饰的方法上,
    • 底层使用了动态代理,并规定了访问权限是public
  3. 注解的方法被标注为final类型
    • 由于底层使用了动态代理,如果设置为final就表示不能生成动态代理对象
  4. 注解的属性rollbackFor设置错误,
    • 默认是RuntimeException以及子类,如果需要支持其他异常需要指明在rollbackFor属性内
  5. 注解的属性propagation设置错误:
    • 默认是REQUIRE,如果设置为NOT_SUPPORT,会因为有事务抛出异常,如果是MANDATORY 则会因为外层没有事务的话导致报错
  6. 注解的方法内异常被手动捕获
    • 底层是方法根据抛出的异常决定是否回滚,如果被捕获了,没有抛出,外层自然拿不到异常
  7. 同一个方法内自调用,导致失效
  8. 注解的方法所属的类没有被spring管理
    1. 比如所在类没有使用@Controller,@Service,@Componment,@Bean等注解
  9. 注解的方法内部采用了多线程调用
    1. 根据事务底层原理,即子线程的状态,主流程线程不能影响到
  10. 嵌套事务导致回滚失效
    1. 根据嵌套事务定义,内存事务回滚不会导致外层事务回滚,外层事务回滚,内存事务也会回滚
(1)方法内自调用导致的事务失效场景

​ 这种场景比较隐蔽,也是比较容易出现问题的场景

@Service
public class UserService{
    
    @Autowired
    private UserMapper userMapper;

    @Transcational
    public void add(User user){
        userMapper.insertUser(user);
        //失效场景之一:方法内直接调用
        updateStatus(user);
    }

    @Transcational
    public void updateStatus(User user){
        user.setStatus(1);
        userMapper.update(user);
    }
}
//解决方式:另外新家一个业务类调用add
@Service
public class ServiceB {
    @Resource
	UserService userService
     @Transcational    
    public void add(user user){
        userService.add(user);
    }
}
(2)方法二:在该类中注入自己
@Service
public class UserService{
    
    @Autowired
    private UserMapper userMapper;
    @Resource
    private UserService userService;
    
    @Transcational
    public void add(User user){
        userMapper.insertUser(user);
        userService.updateStatus(user);
    }
    @Transcational
    public void updateStatus(User user){
        user.setStatus(1);
        userMapper.update(user);
    }
}
(3)方法三:通过AOPContent类或者SpringContext类
@Service
public class UserService{
    
    @Autowired
    private UserMapper userMapper;

    @Resource
    private UserService userService;

    @Transcational
    public void add(User user){
        userMapper.insertUser(user);
        //方式一,使用SpringContext调用
        SpringContext.getBean(this.getClass()).doConvert(convertBO);
        //方式二:使用AopContext,不推荐,需要强转
        //((AssetsConvertService)AopContext.currentProxy()).execute(convertBO);
        
    }
    @Transcational
    public void updateStatus(User user){
        user.setStatus(1);
        userMapper.update(user);
    }
}
7、使用注解式事务需要注意的点
  • @Transactional 只能被应用到public,非final方法上。
  • 用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException(“注释”);)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception(“注释”);)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚:@Transactional(notRollbackFor=RunTimeException.class)
  • @Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅@Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是``元素的出现 开启 了事务行为。
  • @Transactional注解的方法,如果要捕获异常一定要注意,可以在catch方法里面再抛出一个异常,这样外层事务也能够回滚
三、关于注解事务可能造成脏读的解决方案
1、脏数据出现场景伪代码
@Service
public class AccountService{
    
    @Autowired
    private AccountMapper  accountMapper;
    @Autowired
    private AccountService accountService;
    
    @Transactional 
    public void deduct(DeductDTo deductDto){
    	//外层:幂等校验
        RequestValidate(deductDto);
        //中层:分布式锁校验
		RLock lock = redissonClient.getLock("account_lock_"+deductDto.getAcctId());
        boolean lockSuccess = lock.tryLock(60, TimeUnit.SECONDS);
   		if(!lockSuccess){
            throw new BizException("获取锁超时");
        }
        try{
            accountService.doDeduct(deductDto);
        }finally{
             lock.unlock();//释放锁
        }
    }
    
    public void doDeduct(DeductDTo deductDto){
        //第一步查询
            Account account = accountMapper.getById(deductDto.getAccId());
            //第二步,变更account
            Long afterBalance = account.getBalance()-deductDto.getTransNum();
            if(afterBalance<0){
                throw new BizException("余额不足");
            }
            account.setBalance(afterBalance);
            accountMapper.update(account);
            //第三步:记录交易记录
            AccountTranLog tranLog = buildTranLog(deductDto,account);
            accountMapper.saveTranLog(tranLog);
    }
}
2、出现脏数据的原因分析
  • 事务请求突破了接口幂等防范,导致相同的请求在短时间内进入到方法中执行
  • 事务请求突破了分布式锁防范,分布式锁时间设置过段,或者执行完成后释放了锁
  • 第一次请求在事务没有提交时,第二次请求已经读取了Account数据脏数据,随后第一次请求事务提交,第二次事务提交,突破了事务设置
3、场景的解决方案
(1)采用乐观锁的方式(推荐)

修改doDeduct方法,采用乐观锁方式

public void doDeduct(DeductDTo deductDto){
    //第一步查询
    Account account = accountMapper.getById(deductDto.getAccId());
    //第二步,变更account
    Long afterBalance = account.getBalance()-deductDto.getTransNum();
    if(afterBalance<0){
        throw new BizException("余额不足");
    }
    //注意这里需要将原有的值进行一次CAS乐观锁比较
    LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<Account>()
        .set(Account::getBalance,afterBalance)
        .eq(Account::getAccId,account.getAccId())
        .eq(Account::getBalance,account.getBalance());
    Boolean aboolean = accountMapper.update(updateWrapper);
    //如果更新失败则进行回滚
    if(!aBllean){
        throw new BizException("扣减账户余额失败");
    }
    //第三步:记录交易记录
    AccountTranLog tranLog = buildTranLog(deductDto,account);
    accountMapper.saveTranLog(tranLog);
}
(2)缩小事务范围(推荐)

将 @Transactional 放到doDeduct上,这样缩小事务范围,这样就不会因为分布式锁被释放导致第二次请求进入到事务方法

@Transactional     
public void doDeduct(DeductDTo deductDto){
    // ... ... 
}
(3)使用悲观锁(不推荐)

使用synchroinzed,这样会导致整个并发变慢

public synchroinzed void doDeduct(DeductDTo deductDto){
    // ... ... 
}
四、编程式事务
1、创建一个编程式事务的配置类

添加这个类,根据知己需要修改切入点,然后放到能被spring boot扫描到的包下即可

@Aspect
@Configuration
public class GlobalTransactionAdviceConfig {
    private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.example.demo.service..*.*(..))";

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Bean
    public TransactionInterceptor txAdvice() {
        DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
        txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
        txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        txAttr_REQUIRED_READONLY.setReadOnly(true);

        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        source.addTransactionalMethod("add*", txAttr_REQUIRED);
        source.addTransactionalMethod("insert*", txAttr_REQUIRED);
        source.addTransactionalMethod("save*", txAttr_REQUIRED);
        source.addTransactionalMethod("create*", txAttr_REQUIRED);
 		// ... ... 根据方法名称匹配设置对应的事务
        source.addTransactionalMethod("select*", txAttr_REQUIRED_READONLY);
        return new TransactionInterceptor(transactionManager, source);
    }

    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }
}
2、添加User的AOP类

如果事务不在Service下面,而是在Controller中

切入点为controller时,如何使用编程式事务管理控制事务

@Component
@Aspect
public class ResUserAspect {

    @Autowired
    private IPartnerService partnerService;
    @Autowired
    private PlatformTransactionManager platformTransactionManager;
    @Autowired
    private TransactionDefinition transactionDefinition;

    private TransactionStatus transactionStatus;
	// 验证切入点为service时,AOP编程中的事务问题
    @Pointcut("execution(public * com.example.demo.controllers.UserController.insertUser(..))")
    private void insertUser(){}

    @Before(value = "insertUser()")
    public void before(){
        //在切入点程序执行之前手动开启事务 - 必须的操作
        transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
    }
   //切入点为controller时的事务验证
    @Transactional
    @AfterReturning(pointcut = "insertUser()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result){

        if (!(result instanceof JSONMsg)){
            System.out.println(result.getClass());
            return;
        }
        JSONMsg jsonMsg = (JSONMsg) result;
        try{

            if (jsonMsg.getCode() == 200){
                ResPartner partner = new ResPartner();
                ResUser user = (ResUser) jsonMsg.getData();
                partner.setId(user.getId());
                partner.setName(user.getName());
                partner.setDisplayName(user.getLogin());
                int a = 1/0;
                int i = partnerService.add(partner);
                System.out.println(i);
            }

            platformTransactionManager.commit(transactionStatus);  // 手动提交事务
            System.out.println("提交事务");
        }catch (Exception e){
            platformTransactionManager.rollback(transactionStatus); // 出现异常,回滚事务
            System.out.println("回滚事务");
            System.out.println(e.getMessage());

            //修改返回数据
            jsonMsg.setCode(400);
            jsonMsg.setMsg(e.getMessage());
        }

    }
}
五、编程式事务
1、函数式编程式事务工具类
@Slf4j
public class TransactionKit {

    private TransactionKit() {}

    public static <R> R enableTrans(Supplier<R> supplier, int timeout) {
        RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
        rbta.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        rbta.setIsolationLevel(Isolation.DEFAULT.value());
        // 单位秒
        rbta.setTimeout(TransactionDefinition.TIMEOUT_DEFAULT);
        rbta.setReadOnly(false);
        List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
        rollbackRules.add(new RollbackRuleAttribute(RuntimeException.class));
        rbta.setRollbackRules(rollbackRules);
        PlatformTransactionManager txManager = SpringContext.getBean(PlatformTransactionManager.class);
        TransactionStatus transactionStatus = txManager.getTransaction(rbta);

        try {
            R rs = supplier.get();
            txManager.commit(transactionStatus);
            return rs;
        } catch (Exception e) {
            log.error("", e);
            if(TransactionSynchronizationManager.isActualTransactionActive()) {
                txManager.rollback(transactionStatus);
            }
            throw e;
        }
    }

    public static void enableTrans(Runnable runnable, int timeout) {
        RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
        rbta.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        rbta.setIsolationLevel(Isolation.DEFAULT.value());
        // 单位秒
        rbta.setTimeout(timeout);
        rbta.setReadOnly(false);
        List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
        rollbackRules.add(new RollbackRuleAttribute(RuntimeException.class));
        rbta.setRollbackRules(rollbackRules);
        PlatformTransactionManager txManager = SpringContext.getBean(PlatformTransactionManager.class);
        TransactionStatus transactionStatus = txManager.getTransaction(rbta);
        try {
            runnable.run();
            txManager.commit(transactionStatus);
        } catch (Exception e) {
            log.error("", e);
            if(TransactionSynchronizationManager.isActualTransactionActive()) {
                txManager.rollback(transactionStatus);
            }
            throw e;
        }
    }
    /**
     * 开启事务
     */
    public static <R> R enableTrans(Supplier<R> supplier) {
        return enableTrans(supplier, TransactionDefinition.TIMEOUT_DEFAULT);
    }

    public static void enableTrans(Runnable runnable) {
        enableTrans(runnable, TransactionDefinition.TIMEOUT_DEFAULT);
    }

    public static void doAroundTxCommit(Runnable taskBeforeCommit, Runnable taskAfterCommit) {
        if(TransactionSynchronizationManager.isActualTransactionActive()) {

            TransactionSynchronizationManager
                    .registerSynchronization(new TransactionSynchronizationAdapter() {

                        @Override
                        public void beforeCommit(boolean readOnly) {
                            if(readOnly || taskBeforeCommit != null) {
                                log.info("事务提交前执行任务 >>>");
                                taskBeforeCommit.run();
                            }
                        }

                        @Override
                        public void afterCommit() {
                            if(taskAfterCommit != null) {
                                log.info("事务提交后执行任务 >>>");
                                taskAfterCommit.run();
                            }
                        }

                    });
        } else {
            // 无事务 则直接执行

            if(taskBeforeCommit != null) {
                taskBeforeCommit.run();
            }

            if(taskAfterCommit != null) {
                taskAfterCommit.run();
            }
        }
    }

    public static void doBeforeTxCommit(Runnable taskBeforeCommit) {
        if(TransactionSynchronizationManager.isActualTransactionActive()) {
            TransactionSynchronizationManager
                    .registerSynchronization(new TransactionSynchronizationAdapter() {
                        @Override
                        public void beforeCommit(boolean readOnly) {
                            if(readOnly || taskBeforeCommit != null) {
                                log.info("事务提交前执行任务 >>>");
                                taskBeforeCommit.run();
                            }
                        }
                    });
        } else {
            // 无事务 则直接执行
            if(taskBeforeCommit != null) {
                taskBeforeCommit.run();
            }
        }
    }

    public static void doAfterTxCommit(Runnable taskAfterCommit) {
        if(TransactionSynchronizationManager.isActualTransactionActive()) {
            TransactionSynchronizationManager
                    .registerSynchronization(new TransactionSynchronizationAdapter() {
                        @Override
                        public void afterCommit() {
                            if(taskAfterCommit != null) {
                                log.info("事务提交后执行任务 >>>");
                                taskAfterCommit.run();
                            }
                        }
                    });
        } else {
            // 无事务 则直接执行
            if(taskAfterCommit != null) {
                taskAfterCommit.run();
            }
        }
    }

}
六、多线程中使用事务

主要思路:通过多线程的闭锁实现对并发事务的整体控制

1、事务线程池工具类
public class ThreadPoolTool<T> {

    public void excuteTask(DataSourceTransactionManager transactionManager, 
                List data, int threadCount, Map<String, Object> params, Class clazz) {
        if (data == null || data.size() == 0) {
            return;
        }
        int batch = 0;

        ExecutorService executor = Executors.newFixedThreadPool(threadCount);

        //监控子线程的任务执行
        CountDownLatch childMonitor = new CountDownLatch(threadCount);
        //监控主线程,是否需要回滚
        CountDownLatch mainMonitor = new CountDownLatch(1);
        //存储任务的返回结果,返回true表示不需要回滚,反之,则回滚
        BlockingDeque<Boolean> results = new LinkedBlockingDeque<Boolean>(threadCount);
        RollBack rollback = new RollBack(false);

        try {
            LinkedBlockingQueue<List> queue = splitQueue(data, threadCount);
            while (true) {
                List list = queue.poll();
                if (list == null) {
                    break;
                }
                batch++;
                params.put("batch", batch);
                Constructor constructor = clazz.getConstructor(new Class[]{CountDownLatch.class, CountDownLatch.class, BlockingDeque.class, RollBack.class, DataSourceTransactionManager.class, Object.class, Map.class});

                ThreadTask task = (ThreadTask) constructor.newInstance(childMonitor, mainMonitor, results, rollback, transactionManager, list, params);
                executor.execute(task);
            }

            //   1、主线程将任务分发给子线程,然后使用childMonitor.await();阻塞主线程,等待所有子线程处理向数据库中插入的业务。
            childMonitor.await();
            System.out.println("主线程开始执行任务");

            //根据返回结果来确定是否回滚
            for (int i = 0; i < threadCount; i++) {
                Boolean result = results.take();
                if (!result) {
                    //有线程执行异常,需要回滚子线程
                    rollback.setNeedRoolBack(true);
                }
            }
            //  3、主线程检查子线程执行任务的结果,若有失败结果出现,主线程标记状态告知子线程回滚,然后使用mainMonitor.countDown();将程序控制权再次交给子线程,子线程检测回滚标志,判断是否回滚。
            mainMonitor.countDown();

        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            //关闭线程池,释放资源
            executor.shutdown();
        }

    }

    /**
     * 队列拆分
     */
    private LinkedBlockingQueue<List<Object>> splitQueue(List<Object> data, int threadCount) {
        LinkedBlockingQueue<List<Object>> queueBatch = new LinkedBlockingQueue();
        int total = data.size();
        int oneSize = total / threadCount;
        int start;
        int end;

        for (int i = 0; i < threadCount; i++) {
            start = i * oneSize;
            end = (i + 1) * oneSize;
            if (i < threadCount - 1) {
                queueBatch.add(data.subList(start, end));
            } else {
                queueBatch.add(data.subList(start, data.size()));
            }
        }
        return queueBatch;
    }
}
2、子线程城执行事务
public abstract class ThreadTask implements Runnable {
    private CountDownLatch childMonitor;
    private CountDownLatch mainMonitor;
    private BlockingDeque<Boolean> resultList;
    private RollBack rollback;
    private Map<String,Object> params;
    protected Object obj;
    protected DataSourceTransactionManager transactionManager;
    protected TransactionStatus status;

    public ThreadTask(CountDownLatch childCountDown, 
                      CountDownLatch mainCountDown, 
                      BlockingDeque<Boolean> result, 
                      RollBack rollback, 
                      DataSourceTransactionManager transactionManager,
                      Object obj,
                      Map<String,Object> params) {
        this.childMonitor = childCountDown;
        this.mainMonitor = mainCountDown;
        this.resultList = result;
        this.rollback = rollback;
        this.transactionManager = transactionManager;
        this.obj = obj;
        this.params = params;
        initParam();
    }

    /**
     * 事务回滚
     */
    private void rollBack() {
        System.out.println(Thread.currentThread().getName()+"开始回滚");
        transactionManager.rollback(status);
    }

    /**
     * 事务提交
     */
    private void submit() {
        System.out.println(Thread.currentThread().getName()+"提交事务");
        transactionManager.commit(status);
    }

    protected Object getParam(String key){
        return params.get(key);
    }

    /**
      * 初始化方法:作用是把线程池工具任务执行类所需的外部资源通过 ThreadTask.class的构造方法中 Map<String,Obejct> params参数进行初始化传递进来
      */
    public abstract void initParam();

    /**
     * 执行任务,返回false表示任务执行错误,需要回滚
     * @return
     */
    public abstract boolean processTask();

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"子线程开始执行任务");
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        status = transactionManager.getTransaction(def);

        Boolean result = processTask();
        //向队列中添加处理结果
        resultList.add(result);
        //2、使用childMonitor.countDown()释放子线程锁定,同时使用mainMonitor.await();阻塞子线程,将程序的控制权交还给主线程。
        childMonitor.countDown();
        try {
            //等待主线程的判断逻辑执行完,执行下面的是否回滚逻辑
            mainMonitor.await();
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        System.out.println(Thread.currentThread().getName()+"子线程执行剩下的任务");
        //3、主线程检查子线程执行任务的结果,若有失败结果出现,主线程标记状态告知子线程回滚,然后使用mainMonitor.countDown();将程序控制权再次交给子线程,子线程检测回滚标志,判断是否回滚。
        if (rollback.isNeedRoolBack()) {
            rollBack();
        }else{
            //事务提交
            submit();
        }
    }
}
3、线程标记类
@Data
public class RollBack {
    public RollBack(boolean needRoolBack) {
        this.needRoolBack = needRoolBack;
    }

    private boolean needRoolBack;


}
4、线程池工具
/**
 * 多线程处理任务类
 */
public class TestTask extends ThreadTask {

    /**
       分批处理的数据
     */
    private List<Object> objectList;

    /**
     * 可能需要注入的某些服务
     */
    private TestService testService;

    public TestTask(CountDownLatch childCountDown, CountDownLatch mainCountDown, BlockingDeque<Boolean> result, RollBack rollback, DataSourceTransactionManager transactionManager, Object obj, Map<String, Object> params) {
        super(childCountDown, mainCountDown, result, rollback, transactionManager, obj, params);
    }

    @Override
    public void initParam() {
        this.objectList = (List<Object>) getParam("objectList");
        this.testService = (TestService) getParam("testService");
    }


    /**
     * 执行任务,返回false表示任务执行错误,需要回滚
     * @return
     */
    @Override
    public boolean processTask() {
        try {
            for (Object o : objectList) {
                testService.list();
                System.out.println(o.toString()+"执行自己的多线程任务逻辑");
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

}
5、使用示例
/**
 * 执行多线程任务方法
 */
public void testThreadTask() {
    try {
        int threadCount = 5;
        //需要分批处理的数据
        List<Object> objectList = new ArrayList<>();
        Map<String,Object> params = new HashMap<>();
        params.put("objectList",objectList);
        params.put("testService",testService);
        //调用多线程工具方法
        threadPoolTool.excuteTask(transactionManager,objectList,threadCount,params, TestTask.class);
    }catch (Exception e){
        throw new RuntimeException(e.getMessage());
    }
}
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值