Mybatis中 foreach、batch、MyBatisBatchItemWriter批处理性能测试

Mybatis中 foreach、batch、MyBatisBatchItemWriter批处理性能测试

  • Mybatis批处理的几种方式
    • 相关说明必读
    • 1、Mybatis foreach
    • 2、Mybatis batch
    • 3、MyBatisBatchItemWriter
    • 实验结果
    • 结论
    • 思考

Mybatis批处理的几种方式

最近研究到Mybatis-Spring整合包,发现其中对Spring batch(Spring开源的优秀批处理框架)进行了封装,提供了三个简单易用类。MyBatisPagingItemReader(分页读), MyBatisBatchItemWriter(批量写), MyBatisCursorItemReader(游标读),详细内容请看这里,[Mybatis-Spring Spring batch](http://www.mybatis.org/spring/batch.html)
使用Spring batch的封装类进行批量操作,性能如何?相比mybatis的动态sql,Batch模式,性能如何?
本文以三种方式的批量插入数据为例进行简单性能测试,探究下这个问题。

相关说明必读

  1. getUsers()方法进行数据准备,全局指定插入数量如:50,100,500
  2. 通过对比数据插入前后用时进行性能对比
  3. 本此测试使用mysql
  4. batch模式使用,需要添加mysql驱动的支持,添加rewriteBatchedStatements=true配置
    后面给出了两种情况下的实验结果,实验结果耐人寻味。
private List<User> getUsers() {
    ArrayList<User> users = new ArrayList<>();
    while (users.size() < usersNum) {
        users.add(User.builder().age(12).name("bin").id(RandomUtils.nextInt()).build());
    }
    return users;
}

1、Mybatis foreach

<insert id="insertUsers" parameterType="list">
    insert into t_userxxx (id, name, age) values
    <foreach collection="users" item="user" separator=",">
      (#{user.id}, #{user.name}, #{user.age})
    foreach>
insert>
@Test
public void testForeachInsert() {
	List<User> users = getUsers();
	long startTimeMillis = System.currentTimeMillis();
	userMapper.insertUsers(users);
	System.out.println("foreachInsert 共执行" + (System.currentTimeMillis() - startTimeMillis) + "ms");
}

2、Mybatis batch

<insert id="insertUser1" parameterType="User">
  insert into t_user (id, name, age) values(#{id}, #{name}, #{age})
insert>
@Test
public void batchTest() {
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> users = getUsers();
    long startTimeMillis = System.currentTimeMillis();
    for (int i = 0; i < users.size(); i++) {
        User user = users.get(i);
        mapper.insertUser1(user);
    }
    sqlSession.flushStatements();
    System.out.println("batch方式共执行" + (System.currentTimeMillis() - startTimeMillis) + "ms");
}

3、MyBatisBatchItemWriter

@Test
public void testConfigurationUsingSqlSessionTemplate() {
	//通过整合包提供的Builder,构造MyBatisBatchItemWriter
    MyBatisBatchItemWriter<User> itemWriter = new MyBatisBatchItemWriterBuilder<User>()
            .sqlSessionTemplate(new SqlSessionTemplate(this.sqlSessionFactory, ExecutorType.BATCH))
            .statementId("com.zto.xxx.mapper.UserMapper.insertUser1")
            .build();

    //对构造出对itemWriter,进行了校验
    itemWriter.afterPropertiesSet();
    List<User> users = getUsers();
    long startTimeMillis = System.currentTimeMillis();
    itemWriter.write(users);
    System.out.println("itemWriter 执行共计" + (System.currentTimeMillis() - startTimeMillis) + "ms");
}

实验结果

一、jdbcUrl 未添加rewriteBatchedStatements=true
Mybatis中 foreach、batch、MyBatisBatchItemWriter批处理性能测试_第1张图片
二、添加 rewriteBatchedStatements=true
即:jdbc:mysql://10.9.123.111:3306/test?xxxx&rewriteBatchedStatements=true
Mybatis中 foreach、batch、MyBatisBatchItemWriter批处理性能测试_第2张图片

结论

foreach,和batch性能均可,可以日常开发使用,整合提供的Batch封装类,该场景不适合。

思考

  1. foreach性能为何如此强大?
    动态sql,通过foreach标签进行了sql拼接出一个大sql,交由数据库执行,只需一次调用。(不同DB对foreach支持程度不同,业务开发中也不会一次性提交大量数据,通常会给出限制)
  2. 选foreach还是batch模式开发?
    1)mybatis batch模式,需要通过手动设置ExecutorType.BATCH,驱动配置添加 rewriteBatchedStatements=true。相比foreach开发较为麻烦,但性能强大。
    2)foreach使用简单,无需额外配置。
    两者均可用于日常开发,但从上面测试结果看,添加驱动配置后,对simple类型执行性能有所影响,需要根据业务场景选择。如:独立服务中使用batch模式可以避免副作用同时提高数据操作性能。
    3.Spring batch的能力在本次简单批量插入数据中未能发挥出能力,且认为场景不适合,不建议在此类简单数据操作中使用。

你可能感兴趣的:(Mybatis源码分析)