多线程:Runnable批量插入数据到mysql(二)

此篇文章与前面:多线程:Future批量插入数据到mysql(一) 对应的解决同一个问题得两种方法。
即:多线程,向数据库批量插入数据
步骤:第一步,在控制层构造一百万数据(实际开发可能是接收其他地方的数据)

package com.sinux.cc.batchoperate.controller;

import com.sinux.cc.batchoperate.entity.SysUser;
import com.sinux.cc.batchoperate.service.ISysUserService;
import com.sinux.cc.utils.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
/**
 * @author 
 * @since 2020-06-26
 */
@RestController
@RequestMapping("/batchoperate/sys-user")
@Api(tags = "批量操作")
public class SysUserController {
    @Autowired
    private ISysUserService iSysUserService;
    
    @PostMapping("/batchInsertbyrun")
    @ApiOperation(value = "Run方法多线程:批量插入数据")
    public R batchInsertByRun() {
        List<SysUser> list = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            SysUser su = new SysUser();
            su.setUsername("美美" + i);
            su.setPassword("i love you " + i);
            su.setRoleId(i);
            su.setLoginTime(new Date());
            list.add(su);
        }
        boolean a = iSysUserService.batchInsertByRun(list);
        if (a) {
            return R.ok();
        } else {
            return R.error();
        }
    }
}

接口:interface

boolean batchInsertByRun(List<SysUser> list);

②在实现类中调用 runnable(记住:runnable方法的使用)

@Override
    public boolean batchInsertByRun(List<SysUser> list){
        try {
            new Thread(new BatchRunnable(list,sysUserMapper)).start();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

③写好BatchRunnable类处理批量数据(***重点***这个类没有纳入容器管理,所以这里的list和sysUserMapper都是通过构造传过来的,记住这种思维方式)

package com.sinux.cc.batchoperate.util;


import com.sinux.cc.batchoperate.entity.SysUser;
import com.sinux.cc.batchoperate.mapper.SysUserMapper;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class BatchRunnable implements Runnable{
    /**
     * 100条为分界批量导入
     */
    private int batch500 = 500;
    /**mysql数据*/
    private List<SysUser> list;

    private SysUserMapper sysUserMapper;
    ExecutorService executorService = new ThreadPoolExecutor(
            4,
            Runtime.getRuntime().availableProcessors(),
            2L,
            TimeUnit.SECONDS,
            new LinkedBlockingDeque<>(12),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );
    public BatchRunnable(List<SysUser> list,SysUserMapper sysUserMapper){
        System.out.println("当前线程:"+Thread.currentThread().getName());
        this.list=list;
        this.sysUserMapper=sysUserMapper;
    }

    @Override
    public void run() {
        try {
            batchOp(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void batchOp(List<SysUser> list) {
        System.out.println("进入batchOp===集合长度为:"+list.size());
        if(!list.isEmpty()){
            Long t1 = System.currentTimeMillis();
            Integer size = list.size();
            if(size<=batch500){
                sysUserMapper.insertBatch(list);
            }else {
                batchSpilitList(list);
            }
            Long t2 = System.currentTimeMillis();
            System.out.println("插入完毕,用时:"+(t2-t1)+"毫秒");
        }
    }
    private void batchSpilitList(List<SysUser> list) {
        Long t1 = System.currentTimeMillis();
        List<List<SysUser>> lists = new ArrayList<>();
        int i=1;
        try {
            lists = BathUtil.pagingList(list,batch500);
            for(List<SysUser> li : lists){
                System.out.println("第"+i+"批数据正在插入");
                i++;
                executorService.execute(()->{
                    System.out.println("当前线程是:"+Thread.currentThread().getName());
                    batchOp(li);
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            executorService.shutdown();
            Long t2 = System.currentTimeMillis();
            System.out.println("执行完成,用时…………"+(t2-t1));
        }
    }
}

④ list集合的分割方法(记住:通用方法)

public class BathUtil {
    public static <T> List<List<T>> pagingList(List<T> list, int pageSize) {
        int length = list.size();
        System.out.println(pageSize);
        int num = (length + pageSize - 1)/ pageSize;
        List<List<T>> newlist = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            int fromIndex = i * pageSize;
            int toIndex = (i + 1) * pageSize < length ? (i + 1) * pageSize : length;
            newlist.add(list.subList(fromIndex, toIndex));
        }
        return newlist;
    }
}

⑤剩下的就是mapper和xml

void insertBatch(@Param("list") List<SysUser> list);
  <insert id="insertBatch">
        insert into sys_user(
        username,
        password,
        role_id,
        login_time
        )values
        <foreach collection="list" item="item" separator=",">
            (
            #{item.username},
            #{item.password},
            #{item.roleId},
            #{item.loginTime}
            )
        </foreach>
    </insert>

这里的实体类很简单:

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class SysUser implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId
    private int id;
    private String username;
    private String password;
    private Integer roleId;
    private Date loginTime;
}

总结:1.在service层使用runnable的方法。在Future批量插入数据到mysql(一)中讲的是使用future实行多线程,对比总结归纳。
2.BatchRunnable 类的run方法开始使用了线程池处理批量数据插入,小批量插入数据的思维值得注意
3.集合分割BathUtil ,纯粹的技术方法。记住就好,可能会再遇到,这里是个通用的方法
4.xml里面的批量插入数据方法 foreach的使用(用的时候记得去哪里找就行)

  <insert id="insertBatch">
        insert into sys_user( login_time )values
        <foreach collection="list" item="item" separator=",">
            ( #{item.loginTime})
        </foreach>
    </insert>

你可能感兴趣的:(java,mybatis,数据库,mysql)