Mybatis实现大数据量插入

118 阅读1分钟

1. 使用循环进行插入

void insertUserByLoop() {
    // 生成数据
    List<User> users = generateData();
   
    // 循环插入
    for (User user : users) {
        mybatisDemoMapper.insertUser(user);
    }
}

使用这种方式进行大数据量插入的效率最低,因为每次执行SQL都需要创建一个新的SqlSession,并生成PreparedStatement对象,执行完之后再关闭SqlSession。
这种方式适合少量数据的插入。

image.png

2. 使用foreach标签进行插入

mapper.xml文件可以这么写:

<insert id="insertUsers">
    insert into mybatis_demo.user values
    <foreach collection="users" item="user" separator=",">
        <if test="user.id != null and user.id != ''">
            (
            #{user.id},
            #{user.username},
            #{user.password}
            )
        </if>
    </foreach>
</insert>

这种方式会形成一个特别大的SQL,其生成的PreparedStatement中占位符会相当多,解析起来比较费时;同时 Mysql 对执行的SQL语句大小也有限制,默认允许最大4M,若SQL过长,执行也会抛出异常。
这种方式一般适合100行以内的批量插入。 image.png

3. 使用批处理进行插入

void insertUserByBatch() {
    List<User> users = generateData();
    // 批处理方式,关闭自动提交
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
    MybatisDemoMapper mapper = sqlSession.getMapper(MybatisDemoMapper.class);
    for (int i = 0; i < users.size(); i++) {
        mapper.insertUser(users.get(i));
        // 每1000条数据提交一次
        if ((i + 1) % BATCH_SIZE == 0) {
            sqlSession.commit();
        }
    }
    sqlSession.commit();
}

这种方式仅生成一个PreparedStatement,数据库等待需要运行的参数,接收到参数后一次运行,一般来说可以分多次进行批量提交。
这种方式适合大数据量的插入。