这里面记录一下使用mybatis处理mysql的批量插入的问题,测试有可能不准。只愿世间风景千般万般熙攘过后,字里行间,人我两忘,相对无言。
mybatis的批量插入
我们的测试主体类是springboot环境中的一个控制器类,重要的代码如下,在我们的测试中Constants.MAX_BATCH_NUMBER = 10000。
@GetMapping("insert")public voidinsertBatchData() {//构建一个list,大小为1百万条数据
long beginCreateList =System.currentTimeMillis();
List> lists = new ArrayList<>();for (int i = 0; i < 100000; i ++) {
Map map = new HashMap<>();
map.put("userId", i + "");
map.put("username", "huhx" +i);
map.put("password", "124" +i);
map.put("sex", 1);
map.put("address", System.currentTimeMillis());
lists.add(map);
}long endCreateList =System.currentTimeMillis();
logger.debug("创建一个大小为10万的列表,耗时:" + (endCreateList - beginCreateList)); //4103//插入数据
dbSessionTemplateSupport.simpleSqlInsertBatch("user.simpleInsertUserData", lists);long endInsertData =System.currentTimeMillis();
logger.debug("插入10万数据,耗时:" + (endInsertData - endCreateList)); //49649
}
一、我们每10000条数据提交一次事务
public class DbSessionTemplateSupport extendsSqlSessionTemplate {publicDbSessionTemplateSupport(SqlSessionFactory sqlSessionFactory) {super(sqlSessionFactory);
}//支持批量的插入
public void baseInsertBatch(String sqlStatement, List>list) {
SqlSession session= getSqlSessionFactory().openSession(ExecutorType.BATCH, false);if (list == null || list.size() < 1) {return;
}int listSize =list.size();try{//如果提交的列表条数小于提交阀值
if (listSize <=Constants.MAX_BATCH_NUMBER) {for (int i = 0; i < list.size(); i++) {
session.insert(sqlStatement, list.get(i));
}
session.commit();
}else{for (int i = 0; i
session.insert(sqlStatement, list.get(i));
i++;if (i % Constants.MAX_BATCH_NUMBER == 0 || i ==listSize) {
session.commit();
session.clearCache();
}
}
}
}catch(Exception e) {
session.rollback();
e.printStackTrace();
}finally{
session.close();
}
}
}
这种方式处理插入,仍旧比较慢(其实是很慢很慢,可能是我的代码问题,没有统计时间,太慢了)。但是这种方式可以支持oracle,下面的这种方式非常快,但是oracle不支持。
二、采用mysql支持的拼接式插入数据
/*** mysql的批量插入方式,oracle不支持。
*
*@paramsqlStatement
*@paramlist*/
public void simpleSqlInsertBatch(String sqlStatement, List>list) {if (list == null || list.size() < 1) {return;
}//如果提交的列表条数小于提交阀值
List>[] splitLists =CommUtil.splitLists(list, Constants.MAX_BATCH_NUMBER);for (List>tempList : splitLists) {
insert(sqlStatement, tempList);
}
}
我们对原始的列表进行切割,然后依次的插入。每次的插入都是MAX_BATCH_NUMBER条数据。下面是切割的方法
/*** 对一个列表按照splitNum进行分割。
*
*@paramlists
*@paramsplitNum
*@param
*@return
*/
public static List[] splitLists(List lists, intsplitNum) {intlistSize;if (lists == null || (listSize = lists.size()) < 1) {return new ArrayList[0];
}int length = listSize % splitNum == 0 ? listSize / splitNum : listSize / splitNum + 1;//这里面如果用ArrayList,会在50行报错。ArrayList list = new List();这样会报错。
List[] results = newList[length];intfromIndex, toIndex;for (int i = 0; i < length; i++) {
fromIndex= i *splitNum;
toIndex= (fromIndex + splitNum) > listSize ? listSize : (fromIndex +splitNum);
results[i]=lists.subList(fromIndex, toIndex);
}returnresults;
}
插入的sql语句在mybatis中是使用for...each的方式,如下:
INSERT INTO puser
(userId, username, password, address, sex)
VALUES(
#{item.userId},
#{item.username},
#{item.password},
#{item.address},
#{item.sex}
)
10万条数据的分割时间加上插入到mysql数据库,这种方式耗时:15658毫秒。需要注意的是如果常数设置为10万条,也就是第10万插入一次。这种方式会报错的。
友情链接