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);
}