插入5万数据仅用16秒,用PreparedStatement就可以


在这里插入图片描述

1. 前言

最近系统中增加了一个下发数据的功能,由于系统用户量较大,这个需要最后要插入数据库大概5万多条数据,虽然算不上大数据,但是也需要好好考虑性能问题了。
开始用mybatis的批量插入做了一版,整体上分批插入,每批插入3000条(在生产环境试过一次5000条,结果卡了改成对半砍),mapper代码大概如下图,只要程序中计算得到所有列表数据传入insertBatch方法中即可(加了springBoot自带事务)
在这里插入图片描述
情理之外,意料之中,前端发了请求后超过300s没有返回response报错了

2. 多线程方案

这个是从网上抄的方案,直接运行发现确实快了,但是想想人家多线程都是解决百万级别的数据,我这个需求用多线程有点小题大做了,况且生产环境万一发生什么并发类的问题我们这里不太容易定位,因为接触不到内网数据,需要出差到现场,有没有更简洁的方式呢?
因为没用多线程,抄的代码就不贴了

3. PreparedStatement批量插入

基于以前的经验,查询数据量较大时用jdbc直接连数据库比用mybatis的mapper文件快很多,所以就改成用jdbc查数据库,不可避免用到PreparedStatement.executeBatch()方法,这里也有个坑,一定要记得手动管理事务哦!
最终批量插入代码:

private static final int THREAD_COUNT_SIZE = 3000;
    public void batchInsert(List<Product> productList) {
    
    
        long start = System.currentTimeMillis();
        // 分批数
        int round = productList.size() / THREAD_COUNT_SIZE + 1;
        for (int i = 0; i < round; i++) {
    
    
            int startLen = i * THREAD_COUNT_SIZE;
            int endLen = ((i + 1) * THREAD_COUNT_SIZE > productList.size() ? productList.size() : (i + 1) * THREAD_COUNT_SIZE);
            final List<Product> threadList = productList.subList(startLen, endLen);
            Connection conn = JdbcUtil.getConnection();
            StringBuilder sqlBuilder = new StringBuilder();
            sqlBuilder.append("INSERT INTO PRODUCT (ID,PRODUCTNAME,PRODUCTCODE,PRODUCTDESC,PARENTID,")
                    .append("SORT,LEVEL,ORGID,ORGCODE,ORGNAME,ORGPATH,CREATEBY,CREATEUSERID,CREATETIME)")
                    .append("VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
            PreparedStatement preparedStatement = null;
            try {
    
    
                conn.setAutoCommit(false);
                preparedStatement = conn.prepareStatement(sqlBuilder.toString());
                //循环
                for (int k = 0; k < threadList.size(); k++) {
    
    
                    ProductModel u = threadList.get(k);
                    //使用参数对象替换预编SQL语句中的占位符
                    preparedStatement.setString(1, u.getId());
                    preparedStatement.setString(2, u.getProductname());
                    preparedStatement.setString(3, u.getProductcode());
                    preparedStatement.setString(4, u.getProductdesc());
                    preparedStatement.setString(5, u.getParentid());
                    preparedStatement.setString(6, u.getProductmodelpath());
                    preparedStatement.setString(7, u.getSort());
                    preparedStatement.setString(8, u.getLevel());
                    preparedStatement.setString(9, u.getOrgid());
                    preparedStatement.setString(10, u.getOrgcode());
                    preparedStatement.setString(11, u.getOrgname());
                    preparedStatement.setString(12, u.getOrgpath());
                    preparedStatement.setString(13, u.getCreateBy());
                    preparedStatement.setString(14, u.getCreateUserId());
                    preparedStatement.setDate(15, new java.sql.Date(System.currentTimeMillis()));
                    //循环一次就会生成一条sql语句
                    preparedStatement.addBatch();
                }
                preparedStatement.executeBatch();
                conn.commit();
                conn.setAutoCommit(true);
            } catch (SQLException e) {
    
    
                e.printStackTrace();
            }finally {
    
    
                try {
    
    
                    if (preparedStatement != null) {
    
    
                        preparedStatement.close();
                    }
                    if (conn != null) {
    
    
                        conn.close();
                    }
                } catch (SQLException e) {
    
    
                    e.printStackTrace();
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("批量插入耗时:" + (end - start) + "ms");
    }

测试结果,插入50250条数据,耗时16279ms, 这个结果还可以接受。
做个有追求的程序员,朋友们有更好的方式可以讨论下!
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_42887496/article/details/130372039
今日推荐