mybatis百万数据写入数据库分页优化分批处理java代码实现

场景描述:

现在公司是sqlserver到mysql,要用代码实现初始化的数据搬迁工作,暴露出来初始化接口

问题描述:

数据库使用的是mybatis框架,对于有的表,例如97个字段,一百多万条数据,直接就内存溢出了。

耗时日志(同时优化了sql语句筛选了数据,如果是百万的表筛选了一半):

本次操作共耗时:约11秒,约0分钟,共50000条数据
本次操作共耗时:约10秒,约0分钟,共50000条数据
本次操作共耗时:约55秒,约0分钟,共440000条数据
本次操作共耗时:约0秒,约0分钟,共115条数据
本次操作共耗时:约0秒,约0分钟,共1986条数据
本次操作共耗时:约0秒,约0分钟,共1986条数据
本次操作共耗时:约0秒,约0分钟,共1335条数据
本次操作共耗时:约0秒,约0分钟,共1335条数据
本次操作共耗时:约0秒,约0分钟,共22条数据
1
2
3
4
5
6
7
8
9
解决办法:

① mapper.xml优化

传入类型为list集合,使用foreach来遍历拼接语句

insert into oa_workflow_flownode (workflowid, nodeid, nodename, drawxpos, drawypos, nodetype, nodetypeCN, isstart, isreject, isend, version, description ) values ( #{item.workflowid,jdbcType=VARCHAR}, #{item.nodeid,jdbcType=VARCHAR}, #{item.nodename,jdbcType=VARCHAR}, #{item.drawxpos,jdbcType=INTEGER}, #{item.drawypos,jdbcType=INTEGER}, #{item.nodetype,jdbcType=INTEGER}, #{item.nodetypecn,jdbcType=VARCHAR}, #{item.isstart,jdbcType=INTEGER}, #{item.isreject,jdbcType=INTEGER}, #{item.isend,jdbcType=INTEGER}, #{item.version,jdbcType=CHAR}, #{item.description,jdbcType=VARCHAR} ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ② 对需要插入的数据进行分页插入,分页大小自己控制,随手一测就出来,不同的分页使用不同的分页大小

OAController.java中部分代码

//查询OA系统中的workflow_nodelink表数据,导入到bpm系统中的oa_workflow_nodelink表中
public void importOAWorkflowNodelink() throws Exception {
    try {
        //查询OA系统中的workflow_nodelink表数据
        List<OAWorkflowNodelink> recordList = oaWorkflowNodelinkService.getList();
        //加入UUID,这是id
        for (OAWorkflowNodelink oaWFN : recordList) {
            oaWFN.setId(UUID.randomUUID().toString());
            oaWFN.setVersion("systeminit");
        }
        //清空表
        oaWorkflowNodelinkService.deleteAll();
        //导入到bpm系统中的oa_workflow_flownode表中
        batchProcess(OAWorkflowNodelink.class, 10000, recordList);

    } catch (Exception e) {
        e.printStackTrace();
        throw new Exception(this.getClass().getName() + "发生一些错误");
    }
}

/**
 * 对于大量数据的插入操作进行分批处理节约时间
 * 效能就会提升很多很多倍
 *
 * @param type     实例class
 * @param pageSize 分页大小
 * @param list     实例的集合
 */
public void batchProcess(Class type, int pageSize, List list) {

    long start_time = System.currentTimeMillis();//开始执行时间

    //分批数据信息
    int totalSize = list.size(); //总记录数
    int totalPage = totalSize / pageSize; //共N页

    if (totalSize % pageSize != 0) {
        totalPage += 1;
        if (totalSize < pageSize) {
            pageSize = list.size();
        }
    }

    for (int pageNum = 1; pageNum < totalPage + 1; pageNum++) {
        int starNum = (pageNum - 1) * pageSize;
        int endNum = pageNum * pageSize > totalSize ? (totalSize) : pageNum * pageSize;

        if (type == OAWorkflowNodelink.class) {
            oaWorkflowNodelinkService.insertForeach(list.subList(starNum, endNum));
        }

    }

    logger.info("[" + type.getName() + "]本次操作共耗时:约" +
            (System.currentTimeMillis() - start_time) / 1000 + "秒,约" +
            (System.currentTimeMillis() - start_time) / 60000 + "分钟,共" +
            totalPage * pageSize + "条数据");

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
代码遗憾:

真的很想写一个工具类,然后通过工具类来反射达到自己new对象调用方法,因为每个对象里面的调用的方法都是insertForeach,但是ssm通过工厂了,如果我在工具类中通过new controller层对象的实现方式,那么在service层的dao层的注解注入就没有办法注入成功,除非使用spring-mvc.xml来配置bean,如果这样的话,就太麻烦了,所以我在这里就放弃这样,这会使代码更加复杂难读,毕竟还是要留给后人的,我就不恶心他们了。还是直接写在当前使用的controller下好了。

贴一下,如何通过反射实现调用方法,如果那些方法中没有对象是通过注解方式实现的,就可以使用。

import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;

/**

  • 关于此系统的数据库操作工具类

  • @author xiaheshun
    */
    public class DBUtils {

    private static Logger logger = LoggerFactory.getLogger(DBUtils.class);

    /**

    • 对于大量数据的插入操作进行分批处理节约时间

    • pagesize越大,插入越快

    • 自己随便通过数据库测一下那个字段能用多大是最佳的

    • @param type 实例class

    • @param pageSize 分页大小

    • @param list 实例的集合
      */
      public static void batchProcess(Class serviceType, int pageSize, List list) throws Exception {

      long start_time = System.currentTimeMillis();//开始执行时间

      //分批数据信息
      int totalSize = list.size(); //总记录数
      int totalPage = totalSize / pageSize; //共N页

      if (totalSize % pageSize != 0) {
      totalPage += 1;
      if (totalSize < pageSize) {
      pageSize = list.size();
      }
      }

      for (int pageNum = 1; pageNum < totalPage + 1; pageNum++) {
      int starNum = (pageNum - 1) * pageSize;
      int endNum = pageNum * pageSize > totalSize ? (totalSize) : pageNum * pageSize;
      Method insertForeach = serviceType.getMethod(“insertForeach”, List.class);
      insertForeach.invoke(list.subList(starNum, endNum));
      }

      logger.info(“本次操作共耗时:” +
      (System.currentTimeMillis() - start_time) / 1000 + “秒,约” +
      (System.currentTimeMillis() - start_time) / 60000 + “分钟”);

    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

————————————————
版权声明:本文为CSDN博主「XiaHeShun」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/XiaHeShun/article/details/83818500

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值