list分组,多线程处理数据入库

需求:解析上传的文件,将文件里的数据放入到list后,验证数据,符合条件的数据入库,分组多线程处理数据,有异常回滚事务(这里使用的是手动事务)

先贴代码,这是业务代码

package com.sh.service.test.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sh.constant.ListPartConstant;
import com.sh.dao.CustomerDAO;
import com.sh.po.Customer;
import com.sh.service.test.ListPartitionTestService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;

@Service
@Slf4j
public class ListPartitionTestServiceImpl extends ServiceImpl implements ListPartitionTestService  {

    @Resource(name = "threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    @Override
   // @Transactional(value = Transactional.TxType.REQUIRES_NEW)
    public boolean test(List customerList)  {
        // 开启事务
        DefaultTransactionDefinition df = new DefaultTransactionDefinition();
        df.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus transaction = dataSourceTransactionManager.getTransaction(df);

        List> list = ListUtils.partition(customerList, ListPartConstant.PART_SIZE);
        CompletionService completionService = new ExecutorCompletionService<>(threadPoolTaskExecutor);
        List> taskList = new ArrayList<>();
        try{
            for (List customers : list) {
                taskList.add(new Callable() {
                    @Override
                    public Boolean call() throws Exception {
                        List list = new ArrayList<>();
                        for (Customer customer : customers) {
                            // 这里可以验证每条数据的格式
                            
                            // 验证通过后数据放入list
                            list.add(customer);
                            // 调用dao层服务,入库(省略)

                            log.info(customer.getUserName());
                        }
                        return true;
                    }
                });
            }
            for (Callable callable : taskList) {
                completionService.submit(callable);
            }
            for (int i = 0; i < taskList.size(); i++) {
                Boolean res = completionService.take().get(); // 会阻塞,获取结果
                if (res == null || !res) {
                    throw new Exception("线程分组处理失败");
                }
            }
        }catch(Exception e){
            // 回滚数据库
            log.error("处理失败,回滚数据库", e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            dataSourceTransactionManager.rollback(transaction);
            return false;
        }
        // 提交事务
        dataSourceTransactionManager.commit(transaction);
        return true;
    }
}

这是线程池配置

package com.sh.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

@EnableAsync
@Configuration
public class ThreadPoolConfig {

    /**
     * 核心线程池大小
     */
    private static final int CORE_POOL_SIZE = 10;

    /**
     * 最大可创建的线程数
     */
    private static final int MAX_POOL_SIZE = 20;

    /**
     * 队列最大长度100
     */
    private static final int QUEUE_CAPACITY = 100;

    /**
     * 线程池维护线程所允许的空闲时间300
     */
    private static final int KEEP_ALIVE_SECONDS = 300;

    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor eventExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setMaxPoolSize(MAX_POOL_SIZE);
        executor.setCorePoolSize(CORE_POOL_SIZE);
        executor.setQueueCapacity(QUEUE_CAPACITY);
        executor.setKeepAliveSeconds(KEEP_ALIVE_SECONDS);
        // 线程池对拒绝任务(无线程可用)的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

 事务配置

package com.sh.config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

@Configuration
public class Config {
    
    // 创建事务管理器
    @Bean(name = "dataSourceTransactionManager")
    public DataSourceTransactionManager txManager(@Qualifier("dataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

常量,控制分组大小

package com.sh.constant;

public interface ListPartConstant {


   int PART_SIZE = 5000;
}

你可能感兴趣的:(java后端,java,spring)