java 批量导入数据(新增、更新)

备注:

两种方法:批量修改,新增 application.yml //允许多条数据,否则mybatis 插入数据报错

&allowMultiQueries=true

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://ip地址:3306/数据库名?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
    username: 账号
    password: 密码

(1)方法一
通过id等唯一性字段比较,获取updateList 和 insertList

  List<String> list = operationLogService.getAllIdList();
                List<OperationLog> updList = new ArrayList<>();
                List<OperationLog> insertList = new ArrayList<>();
                for (int i =0 ; i < operationLogs.size(); i++) {
                    OperationLog temp = operationLogs.get(i);
                    if (list.contains(String.valueOf(temp.getId())) ){
                        updList.add(temp);
                    } else {
                        insertList.add(temp);
                    }
                }
                boolean b = false;
                if(insertList.size() > 0){
                    List<List<OperationLog>> listIns = ListUtil.averageAssign(insertList, 1000);
                    for(List<OperationLog> list1: listIns) {
                        b = operationLogService.batchInsert(list1);
                    }
                }

                if(updList.size() > 0 ){
                    List<List<OperationLog>> listUpd = ListUtil.averageAssign(updList, 500);
                    for(List<OperationLog> list2: listUpd) {
                        b = operationLogService.batchUpdate(list2);
                    }
                }
	List 集合拆分
public static <T> List<List<T>> averageAssign(List<T> source, int splitItemNum) {
        List<List<T>> result = new ArrayList<List<T>>();

        if (source != null && source.size() > 0 && splitItemNum > 0) {
            if (source.size() <= splitItemNum) {
                // 源List元素数量小于等于目标分组数量
                result.add(source);
            } else {
                // 计算拆分后list数量
                int splitNum = (source.size() % splitItemNum == 0) ? (source.size() / splitItemNum) : (source.size() / splitItemNum + 1);

                List<T> value = null;
                for (int i = 0; i < splitNum; i++) {
                    if (i < splitNum - 1) {
                        value = source.subList(i * splitItemNum, (i + 1) * splitItemNum);
                    } else {
                        // 最后一组
                        value = source.subList(i * splitItemNum, source.size());
                    }
                    result.add(value);
                }
            }
        }
        return result;
    }

第二种办法

经过测试,批量更新比较慢,可以优化为 先删后全部插入的方案,提高相应时间

  List<String> list = operationLogService.getAllIdList();
                List<Integer> updList = new ArrayList<>();
                for (int i =0 ; i < operationLogs.size(); i++) {
                    OperationLog temp = operationLogs.get(i);
                    if (list.contains(String.valueOf(temp.getId())) ){
                        updList.add(temp.getId());
                    }
                }
                boolean b = false;
                if(updList.size() > 0 ){
                    operationLogService.removeByIds(updList);
                }
                if(operationLogs.size() > 0){
                    List<List<OperationLog>> listIns = ListUtil.averageAssign(operationLogs, 1000);
                    for(List<OperationLog> list1: listIns) {
                        b = operationLogService.batchInsert(list1);
                    }
                }

第三种方案

	采用线程池批量执行,进一步提高执行速度

    public boolean threadMethod(List<OperationLog> updateList) {
        boolean res = false;
        // 初始化线程池,、
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 60,
                4, TimeUnit.SECONDS, new ArrayBlockingQueue(10), new ThreadPoolExecutor.CallerRunsPolicy());
        // 大集合拆分成N个小集合、
        try{
            List<List<OperationLog>> splitNList = ListUtil.averageAssign(updateList, 100);
            // 记录单个任务的执行次数
            CountDownLatch countDownLatch = new CountDownLatch(splitNList.size());
            // 对拆分的集合进行批量处理, 先拆分的集合, 再多线程执行
            for (List<OperationLog> singleList : splitNList) {
                // 线程池执行
                threadPool.execute(new Thread(new Runnable(){
                    @Override
                    public void run() {
                        if (singleList.size() > 0) {
                            operationLogService.batchUpdate(singleList);
                            // 任务个数 - 1, 直至为0时唤醒await()
                            countDownLatch.countDown();
                        }
                    }
                }));
            }
            countDownLatch.await();
            res = true;
        }catch (Exception e){
            res = false;
            e.printStackTrace();
        }finally {
            threadPool.shutdown();
        }
        return res;
    }

附录,其他模块
mapper

  boolean batchInsert(List<OperationLog> list);

    boolean batchUpdate(List<OperationLog> list);

xml

<select id="getAllIdList"  resultType="String" >
        select id from xxx order by id
    </select>

    <insert id="batchInsert" parameterType="com.highguard.sct.auditModule.entity.OperationLog">
        insert into xxx (id, user_name, ...)
        values
        <foreach collection="list" item="item" separator=",">
            (
            #{item.id}, #{item.userName}, ...
            )
        </foreach>
    </insert>



    <update id="batchUpdate" parameterType="com.highguard.sct.auditModule.entity.OperationLog">
        <foreach collection="list" item="item" index="index" separator=";">
            update xxx set
            <if test="item.userName != null and item.userName !=''">
                user_name = #{item.userName},
            </if>
            <if test="item.userRole != null and item.userRole !=''">
                user_role = #{item.userRole},
            </if>
            ...
            createtime = #{item.createtime}
            <where>
                id = #{item.id}
            </where>
        </foreach>
    </update>

foreach foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。 foreach元素的属性主要有
item,index,collection,open,separator,close。

item集合中每一个元素进行迭代时的别名, index表示在迭代过程中,每次迭代到的位置, open该语句以什么开始,
separator在每次进行迭代之间以什么符号作为分隔 符, close以什么结束,
在使用foreach的时候最关键的也是最容易出错的就是collection属性, 该属性是必须指定的,但是在不同情况
下,该属性的值是不一样的, 主要有一下3种情况:
1.如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
2.如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
3.如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了

insert into shop_coupon_record( id, coupon_id, pick_date_time, use_date_time, member_id, is_use, create_date_time, delete_status ) select #{item.id}, #{item.couponId}, #{item.pickDateTime}, #{item.useDateTime}, #{item.memberId}, #{item.isUse}, #{item.createDateTime}, #{item.deleteStatus} from dual
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值