springboot 集成的 mybatis 设置 executorType 为 batch 模式

目录

三种执行器

mybatis 提供三种 sql 执行器,分别是 SIMPLE(默认)、REUSE、BATCH。

  • SIMPLE(SimpleExecutor),相当于 JDBC 的 stmt.execute(sql) 执行完毕即关闭即 stmt.close()

  • REUSE(ReuseExecutor),相当于 JDBC 的 stmt.execute(sql) 执行完不关闭,而是将 stmt 存入 Map<String, Statement> 中缓存,其中 key 为执行的 sql 模板;

  • BATCH(BatchExecutor),相当于 JDBC 语句的 stmt.addBatch(sql),即仅将执行SQL加入到批量计划但是不真正执行, 所以此时不会执行返回受影响的行数,而只有执行stmt.execteBatch()后才会真正执行sql

三种方式各有利弊

方式优势劣势
SIMPLE默认执行器, 节约服务器资源每次都要开关 Statement
REUSE提升后端接口处理效率每次一个新 sql 都缓存,增大 JVM 内存压力
BATCH专门用于更新插入操作,效率最快对 select 不适用,另外特殊要求,比如限制一次 execteBatch 的数量时需要写过滤器定制

设置为 batch 模式

springboot 下开启 batch 模式比较简单,

全局方式开通 batch

在 yml 文件中添加 如下配置即可。

mybatis:
 executor-type: batch

原因是 mybatis-spring-boot 源码,this.properties 就是读取了 yml 中的内容:

@Bean
    @ConditionalOnMissingBean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        ExecutorType executorType = this.properties.getExecutorType();
        if (executorType != null) {
            return new SqlSessionTemplate(sqlSessionFactory, executorType);
        } else {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    }

方法中直接指定 batch

这个方式的缺陷就是事务方面不受 spring 管理了。

@Autowired
    protected SqlSessionFactory sqlSessionFactory;
    
    public void saveOrder(Order t) {
		SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
		OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
		
		try{
			orderMapper.save(t);
			sqlSession.commit();
		}catch(Exception e){
			logger.error("批量导入数据异常,事务回滚", e);
			sqlSession.rollback();
		}finally {
			if (sqlSession != null) {
		  		sqlSession.close();
			}
	}
}

后记

如果单纯的数据同步,其实可以建议 原生 JDBC !, 当然可以采用封装的 JDBC 工具类,真心快的一笔!

// 从spring管理的数据源中直接拿
    @Resource(name = "dataSource")
    private DataSource dataSource;
    
    @Test
    public void jdbcTest() throws SQLException {
        Connection connection = dataSource.getConnection();
        connection.setAutoCommit(false);
        String sql = "INSERT INTO tpm_user (id,name,createDate,remark) VALUES(?,?,?,?) ";

        PreparedStatement statement = connection.prepareStatement(sql);
        for (int i = 0; i < 1000000; i++) {
            statement.setLong(1, snowflakeService.nextId());
            statement.setString(2, "name" + i);
            statement.setDate(3, new Date(System.currentTimeMillis()));
            statement.setString(4, "remark" + i);
            statement.addBatch();
        }
        long start = System.currentTimeMillis();
        statement.executeBatch();
        connection.commit();
        
        statement.close();
        connection.close();
        System.out.print("耗时:");
        System.out.println(System.currentTimeMillis() - start);
    }