美文网首页
Mybatis批量插入

Mybatis批量插入

作者: justlinzhihe | 来源:发表于2021-11-19 20:02 被阅读0次

    测试表结构
    create table batch_test ( id int auto_increment primary key, username varchar(20) not null, password varchar(100) not null, address varchar(100) null );
    随机生成10w条数据

        private List<BatchTestDO> generateData() {
            List<BatchTestDO> list = new ArrayList<>();
            for (int i = 0; i < 100000; i++) {
                BatchTestDO entity = new BatchTestDO();
                entity.setUsername("小明" + i);
                entity.setPassword(UUID.randomUUID().toString());
                entity.setAddress(UUID.randomUUID().toString());
                list.add(entity);
            }
            return list;
        }
    

    1.mybatis的BatchExecutor
    数据库连接配置:url: jdbc:mysql://127.0.0.1:3306/test?rewriteBatchedStatements=true,主要就是rewriteBatchedStatements这个参数

        @Test
        public void test001() throws Exception {
            List<BatchTestDO> data = generateData();
            long start=System.currentTimeMillis();
            SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
            batchTestMapper=session.getMapper(BatchTestMapper.class);
            for (BatchTestDO datum : data) {
                batchTestMapper.insert(datum);
            }
            session.commit();
            System.out.println(String.format("用时:%d",System.currentTimeMillis()-start));
    
        }
    
    image.png

    十万数据插入4634ms
    2.用jdbc驱动原始的批量提交方式

        @Test
        public void test002() throws SQLException {
            List<BatchTestDO> data = generateData();
            Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?rewriteBatchedStatements=true","root","123456abc");
            long start=System.currentTimeMillis();
            connection.setAutoCommit(false);
            PreparedStatement ps = connection.prepareStatement(
                    "insert into batch_test (username,password,address) values(?,?,?)");
            for (int i = 0; i < data.size(); i++) {
                BatchTestDO batchTestDO=data.get(i);
                ps.setString(1,batchTestDO.getUsername());
                ps.setString(2,batchTestDO.getPassword());
                ps.setString(3,batchTestDO.getAddress());
                ps.addBatch();
            }
            ps.executeBatch();
            connection.commit();
            System.out.println(String.format("用时:%d",System.currentTimeMillis()-start));
            connection.close();
        }
    
    image.png

    只用了2486ms
    3.用foreach标签的方式

        @Insert("<script>" +
                "insert into batch_test (username,password,address) values" +
                "<foreach collection='list' item='entity' separator=','>" +
                "(#{entity.username},#{entity.password},#{entity.address})" +
                "</foreach>" +
                "</script>")
        int batchInsert(@Param("list") List<BatchTestDO> list);
    
        @Test
        public  void test003(){
            List<BatchTestDO> data = generateData();
            long start=System.currentTimeMillis();
            batchTestMapper.batchInsert(data);
            System.out.println(String.format("用时:%d",System.currentTimeMillis()-start));
        }
    
    image.png

    用了5303ms

    4.mybatis-plus的批量插入方式

        @Test
        public void test004(){
            List<BatchTestDO> data = generateData();
            long start=System.currentTimeMillis();
            batchTestMapper.insertBatchSomeColumn(data);
            System.out.println(String.format("用时:%d",System.currentTimeMillis()-start));
        }
    
    image.png

    用了5163ms

    以上程序执行的时候,打开数据库的general_log日志配置,可以看到他们发送到mysql服务端的sql语句都是一样的,insert into table (a,b,c) values (x,x,x),(x,x,x)...这样的

    image.png

    测试用例2的速度比1 3 4都快的原因,个人认为应该是在于mybatis框架在读取对应字段值的时候用的java反射导致的耗时。

    接下来说下rewriteBatchedStatements的作用,这个参数的意义是:在底层jdbc是通过测试用例2这样的批量处理的方式插入数据的时候,如果rewriteBatchedStatements设为true,jdbc驱动就会把sql在本地客户端拼接成insert into table (a,b,c) values (x,x,x),(x,x,x)...这样的sql发送到服务端(这里注意,数据量很多的时候,并不会把所有数据拼接成一条sql,而是分批次拼接,因为mysql每次传输的sql大小是有限制的),否则测试用例2这样的批量插入和一条一条数据的插入没有任何区别。

    接下来就把rewriteBatchedStatements去掉再测一遍

    image.png

    290秒。。。。。


    image.png

    43秒


    image.png
    5535ms
    image.png
    5686ms

    测试用例1,2用了很长时间,结合mysql日志可以看到都是一条条单独的inert语句,而3和4之所以不影响是因为他们拼接sql的操作是在mybatis里完成的而不是jdbc驱动,至于1和2在这种情况下为什么会差这么多,暂时还没找到原因

    相关文章

      网友评论

          本文标题:Mybatis批量插入

          本文链接:https://www.haomeiwen.com/subject/thfetrtx.html