Mysql数据库批量插入大量数据时经常会遇到插入速度过慢的场景;自己也知道批量插入比单条插入也会快很多,后面测试又发现代码也得也没有问题可是执行结果总是差强人意,我也在测试过程中遇到此问题,后面发现是由于URL中缺少了参数导致: rewriteBatchedStatements=true
此参数默认配置是false,需要手动在URL中配置成true进行开启;开启了配置之后,就可以正常使用批量插入了,下面直接上Mybaits和Jdbc批处理的代码
-
Mybatis批处理
try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false)) {
// 获取Mapper,一定要重新获取,否则不会走批处理
XxMapper mapper = sqlSession.getMapper(XxMapper.class);
// 循环插入数据
for (Info info: infos) {
mapper.insert(info);
}
// 批量提交
sqlSession.commit();
}
Mybatis批处理一定要从会话中获取Mapper对象;创建会话的过程会创建执行器并将执行器封装到会话中;创建执行器过程可以参考下面代码
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
// 根据执行类型创建执行器
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
会话创建完成后,从会话中获取到的Mapper对象,调用Mapper对象的方法,会由JDK最终代理到会话中的执行器进行执行,会话又会交由执行器执行;可以参考下面代码
@Override
public int update(String statement, Object parameter) {
try {
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
// 执行器执行更新
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
Jdbc批处理
String sql = "INSERT INTO TABLE(ID, USER_ID, USER_NO) VALUES(?, ?, ?)";
try (Connection connection = dataSource.getConnection();
PreparedStatement stmt = connection.prepareStatement(sql)) {
// 关闭事务的自动提交
connection.setAutoCommit(false);
for (Info info: infos) {
stmt.setString(1, info.getId());
stmt.setString(2, info.getUserId());
stmt.setString(3, info.getUserNo());
// 添加到批处理
stmt.addBatch();
}
// 执行批处理
stmt.executeBatch();
// 事务提交
connection.commit();
} catch (Exception e) {
e.printStackTrace();
}
总结
如果批量插入的数据量在一万条以内的话,使用Mybatis的批处理与Jdbc的批处理在性能上区别不是很大;超过一万条的话还是建议使用Jdbc的批处理,性能上会好一些。