1.问题产生原因
-
SqlServer对语句的条数和参数的数量都有限制,分别是1000和2100
-
Mysql对语句的长度有限制,默认是4M
-
Mybatis对动态语句没有数量上的限制。
2.解决办法
mybatis中ExecutorType的使用
Mybatis内置的ExecutorType有3种,SIMPLE、REUSE、BATCH; 默认的是simple,该模式下它为每个语句的执行创建一个新的预处理语句,单条提交sql;而batch模式重复使用已经预处理的语句,并且批量执行所有更新语句,显然batch性能将更优;但batch模式也有自己的问题,比如在Insert操作时,在事务没有提交之前,是没有办法获取到自增的id,这在某型情形下是不符合业务要求的;
插入大量数据的解决方案,使用ExecutorType
@Autowired
private SqlSessionTemplate sqlSessionTemplate;
public void insertExcelData( List<ExcelEntity> orderList) {
//如果自动提交设置为true,将无法控制提交的条数,改为最后统一提交,可能导致内存溢出
SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
//不自动提交
try {
ExcelEntity userDao = session.getMapper(ExcelEntity.class);
for (int i = 0; i < orderList.size(); i++) {
execlDao.importExeclDate2(orderList.get(i));
if (i % 400 == 0 || i == orderList.size() - 1) {
//手动每400条提交一次,提交后无法回滚
session.commit();
//清理缓存,防止溢出
session.clearCache();
}
}
} catch (Exception e) {
//没有提交的数据可以回滚
session.rollback();
} finally {
session.close();
}
}
这里采用的是单条插入,直接使用for循环,但是使用ExecutorType.BACTH就相当于手动提交。这也是我们需要的效果,所以我们在循环里面判断了,是否到了第400笔,如果到了第400笔就直接提交,然后清空缓存,防止溢出。这样就有效的实现了批量插入,同时保证溢出问题的不出现
int beginIndex = 0;
if (readManagers.size() > 0) {
int endIndex = 0;
int limit = 200;
for (; beginIndex < readManagers.size(); ) {
endIndex = beginIndex + limit;
if (endIndex > readManagers.size() - 1) {
endIndex = readManagers.size() - 1;
}
readBookOperatorDao.updateReadManagerOperator(readManagers.subList(beginIndex, endIndex + 1));
beginIndex = endIndex + 1;
}
}
作者:find_me
链接:mysql和sql server数据库批量插入数据 报错8003 - 掘金