zoukankan      html  css  js  c++  java
  • mysql基础---->mybatis的批量插入(一)

      这里面记录一下使用mybatis处理mysql的批量插入的问题,测试有可能不准。只愿世间风景千般万般熙攘过后,字里行间,人我两忘,相对无言。

    mybatis的批量插入

    我们的测试主体类是springboot环境中的一个控制器类,重要的代码如下,在我们的测试中Constants.MAX_BATCH_NUMBER = 10000。

    @GetMapping("insert")
    public void insertBatchData() {
        // 构建一个list,大小为1百万条数据
        long beginCreateList = System.currentTimeMillis();
        List<Map<String, Object>> lists = new ArrayList<>();
        for (int i = 0; i < 100000; i ++) {
            Map<String, Object> map = new HashMap<>();
            map.put("userId", i + "");
            map.put("username", "huhx" + i);
            map.put("password", "124" + i);
            map.put("sex", 1);
            map.put("address", System.currentTimeMillis());
            lists.add(map);
        }
        long endCreateList = System.currentTimeMillis();
        logger.debug("创建一个大小为10万的列表,耗时:" + (endCreateList - beginCreateList)); // 4103
    
        // 插入数据
        dbSessionTemplateSupport.simpleSqlInsertBatch("user.simpleInsertUserData", lists);
        long endInsertData = System.currentTimeMillis();
        logger.debug("插入10万数据,耗时:" + (endInsertData - endCreateList)); // 49649
    }

    一、我们每10000条数据提交一次事务

    public class DbSessionTemplateSupport extends SqlSessionTemplate {
    
        public DbSessionTemplateSupport(SqlSessionFactory sqlSessionFactory) {
            super(sqlSessionFactory);
        }
    
        // 支持批量的插入
        public void baseInsertBatch(String sqlStatement, List<Map<String, Object>> list) {
            SqlSession session = getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
            if (list == null || list.size() < 1) {
                return;
            }
            int listSize = list.size();
            try {
                // 如果提交的列表条数小于提交阀值
                if (listSize <= Constants.MAX_BATCH_NUMBER) {
                    for (int i = 0; i < list.size(); i++) {
                        session.insert(sqlStatement, list.get(i));
                    }
                    session.commit();
                } else {
                    for (int i = 0; i < list.size(); ) {
                        session.insert(sqlStatement, list.get(i));
                        i++;
                        if (i % Constants.MAX_BATCH_NUMBER == 0 || i == listSize) {
                            session.commit();
                            session.clearCache();
                        }
                    }
                }
            } catch (Exception e) {
                session.rollback();
                e.printStackTrace();
            } finally {
                session.close();
            }
        }
    }

    这种方式处理插入,仍旧比较慢(其实是很慢很慢,可能是我的代码问题,没有统计时间,太慢了)。但是这种方式可以支持oracle,下面的这种方式非常快,但是oracle不支持。

    二、采用mysql支持的拼接式插入数据

    /**
     * mysql的批量插入方式,oracle不支持。
     *
     * @param sqlStatement
     * @param list
     */
    public void simpleSqlInsertBatch(String sqlStatement, List<Map<String, Object>> list) {
        if (list == null || list.size() < 1) {
            return;
        }
        // 如果提交的列表条数小于提交阀值
        List<Map<String, Object>>[] splitLists = CommUtil.splitLists(list, Constants.MAX_BATCH_NUMBER);
        for (List<Map<String, Object>> tempList : splitLists) {
            insert(sqlStatement, tempList);
        }
    }

    我们对原始的列表进行切割,然后依次的插入。每次的插入都是MAX_BATCH_NUMBER条数据。下面是切割的方法

    /**
     * 对一个列表按照splitNum进行分割。
     *
     * @param lists
     * @param splitNum
     * @param <T>
     * @return
     */
    public static <T> List<T>[] splitLists(List<T> lists, int splitNum) {
        int listSize;
        if (lists == null || (listSize = lists.size()) < 1) {
            return new ArrayList[0];
        }
        int length = listSize % splitNum == 0 ? listSize / splitNum : listSize / splitNum + 1;
        // 这里面如果用ArrayList,会在50行报错。ArrayList list = new List();这样会报错。
        List<T>[] results = new List[length];
        int fromIndex, toIndex;
        for (int i = 0; i < length; i++) {
            fromIndex = i * splitNum;
            toIndex = (fromIndex + splitNum) > listSize ? listSize : (fromIndex + splitNum);
            results[i] = lists.subList(fromIndex, toIndex);
        }
        return results;
    }

    插入的sql语句在mybatis中是使用for...each的方式,如下:

    <!-- mysql的批量插入方式 -->
    <insert id="simpleInsertUserData" parameterType="java.util.List">
        INSERT INTO puser
          (userId, username, password, address, sex)
        VALUES
        <foreach collection ="list" item="item" index= "index" separator =",">
            (
            #{item.userId},
            #{item.username},
            #{item.password},
            #{item.address},
            #{item.sex}
            )
        </foreach >
    </insert>

     10万条数据的分割时间加上插入到mysql数据库,这种方式耗时:15658毫秒。需要注意的是如果常数设置为10万条,也就是第10万插入一次。这种方式会报错的。

    友情链接

  • 相关阅读:
    【C/C++】例题5-4 反片语/算法竞赛入门经典/C++与STL入门/映射:map
    【VSCode】如何打开全屏模式/退出全屏模式
    【合同】电子科技大学/外协合同/采购合同
    新的开始
    ubuntu server 1604 搭建FTP服务器
    vim的查找功能
    Ubuntu改坏sudoers后无法使用sudo的解决办法
    ubuntu server 1604 配置网络信息
    ubuntu server 1604 关机和重启
    ubuntu server 1604 设置笔记本盒盖 不操作
  • 原文地址:https://www.cnblogs.com/huhx/p/baseusemysqlbatchinsert1.html
Copyright © 2011-2022 走看看