MyBatis踩坑系列1:浅谈MyBatis的三种批量插入方式

本文介绍了MyBatis的三种批量插入方式:循环执行单条SQL、SQL拼接(foreach)和批处理。通过案例分析了不同方式在大量数据插入时的性能和限制,强调在实际应用中需根据数据量和性能需求选择合适的方法,避免资源浪费和程序错误。

MyBatis踩坑系列1:浅谈MyBatis的三种批量插入方式

序言

每个人在刚刚接触mybatis框架的时候,或多或少会写出一些令程序执行效率变慢的代码。例如:在for循环里写sql。博主刚刚开始写项目的时候,就写过一段双层for循环中做查询、插入、删除、修改的神操作。现在看来当时程序能够顺利上线得亏在于使用人数不多。我们都知道执行一条sql语句就需要访问数据库一次数据库,频繁和数据库进行交互,将是一个十分消耗服务器性能的行为。下面我将带大家带来三种mybatis批量插入的方式,以及各自的优缺点对比。

环境介绍

MySQL5.7+SpringBoot+mybatis+tkmapper

1.我是新手我怕谁——循环体中执行单条sql

在循环体中写入sql是我们新手入门的必经阶段,因为在循环体中写sql可以使得代码更加的直观,让自己的程序跟随自己的思路走下去,从而不增加代码的复杂度。那我们看一看这种方式在100万条插入数据下的表现吧

  /**
     * 循环体中的插入操作
     * @param testList
     * @return
     */
    public long test1(List<Test> testList){
        long start = System.currentTimeMillis();
        for (Test test : testList) {
            testMapper.insertSelective(test);
        }
        long end = System.currentTimeMillis();
        return end-start;
    }

执行结果:
循环体中写SQL

注意:循环体中访问数据库,可以在不追求性能的情况下使用。新手练习也可以多使用来增加对业务的理解,但十分消耗服务器资源切勿上生产使用

2.‘五秒’真男人,谁能有我快——sql拼接

有的人就会说,我才不会在循环体中写sql呢!我可是拥有3年开发经验的老鸟,在xml中写foreach就行了,谁能有我快。那我们看一下他在百万级数据下的表现吧:

@Insert("<script> " +
            " insert into test(name) values " +
            " <foreach collection=\"list\" item=\"item\" index=\"index\" separator=\",\">\n" +
            "        (#{item.name}) </foreach>" +
            "</script>")
    Integer insertList(@Param("list") List<Test> testList);

    /**
     * 拼接sql
     * @param testList
     * @return
     */
    public long test2(List<Test> testList){
        long start = System.currentTimeMillis();
        Integer successNum = testMapper.insertList(testList);
        System.out.println(successNum);
        long end = System.currentTimeMillis();
        return end-start;
    }

执行结果:
sql拼接
**注意:使用mybatis的foreach 本质上是对sql语句的拼接,你的数据量越大,拼接的sql语句越长,可能超过执行的最长sql语句从而程序报错,所以在不确定数据量的情况下优先使用批处理 **

3.我的内涵你不懂——批处理

在第一次看到批处理代码的时候,你可能会认为是一个新手写的代码。在循环体中写sql,可不是一个新手的吗?那我们来看一下他在百万级数据下的表现吧:

@Autowired
    private SqlSessionFactory sqlSessionFactory;

    /**
     * 批处理
     * @param testList
     * @return
     */
    public long test3(List<Test> testList){
        long start = System.currentTimeMillis();
        SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH,false);
        int count=0;
        TestMapper mapper = session.getMapper(TestMapper.class);
        for (Test test : testList) {
            mapper.insertSelective(test);
            count++;
            if(count%1000==999){//每1000条提交一次防止内存溢出
                session.commit();
                session.clearCache();
            }
        }
        session.commit();
        session.clearCache();
        long end = System.currentTimeMillis();
        return end-start;
    }

执行结果:
批处理
注意:使用批处理的前提是已知数据量不大的情况下使用,在数据量尚可的情况下我们还是需要去追求效率。可预知数据量不会超过sql长度下,建议使用mybatis的sql拼接

宏观展示
循环体内SQL拼接SQL批处理
94668毫秒报错45206毫秒
总结

我们在写代码的过程中,不能只考虑逻辑的简单性也不能只考虑性能的高低。需要从实际需求入手,在数据过多时我们常用的sql拼接会使程序报错。在数据量可预知的情况下,如果只是少量的可预知数据我们可以用sql拼接,在大的数据量的情况下,又得考虑性能的情况下可以使用批处理来解决。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不安分学徒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值