需求
测试向数据库里插入10000条数据,分别使用三种插入方式,比较三种方式的效率,
方式一
简单循环插入
@Autowired
private UserMapper userMapper;
/**
* 通过简单循环批量插入
* @throws Exception
*/
@Test
public void testInsertBatch1() throws Exception {
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
User user = User.builder().age(i).name("zhangsan" + i).password(i + "xxxx").sex("男").build();
int insert = userMapper.insert(user);
System.out.println(insert);
}
long end = System.currentTimeMillis();
System.out.println("-------时间3188--------" + (start - end) + "---------------");
}
方式二
通过session使用批量模式插入数据
@Autowired
private SqlSessionTemplate sqlSessionTemplate;
/**
* session使用批量模式插入数据
*/
@Test
public void testInsertBatch2() {
long start = System.currentTimeMillis();
//跟上述sql区别,将session设置为批量形式
SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory()
.openSession(ExecutorType.BATCH, false);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
for (int i = 0; i < 10000; i++) {
User user = User.builder().age(i).name("zhangsan" + i).password(i + "xxxx").sex("男").build();
int insert = mapper.insert(user);
System.out.println(insert);
}
sqlSession.commit();
long end = System.currentTimeMillis();
System.out.println("----时间1535-----------" + (start - end) + "---------------");
}
方式三
通过foreach标签完成批量插入
@Autowired
private UserMapper userMapper;
@Test
public void testInsertBatch3() {
long start = System.currentTimeMillis();
List<User> list = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
User user = User.builder().age(i).name("zhangsan" + i).password(i + "xxxx").sex("男").build();
list.add(user);
}
int i = userMapper.insertBatch(list);
System.out.println(i);
long end = System.currentTimeMillis();
System.out.println("----时间824-----------" + (start - end) + "---------------");
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhanghw.mybatisbatch.mapper.UserMapper">
<insert id="insert">
INSERT INTO user ( name,password,sex,age)
VALUES( #{name}, #{password}, #{sex}, #{age})
</insert>
<insert id="insertBatch" parameterType="com.zhanghw.mybatisbatch.entity.User">
INSERT INTO user (name,password,sex,age)
VALUES
<foreach collection ="list" item="user" separator =",">
(#{user.name}, #{user.password}, #{user.sex}, #{user.age})
</foreach >
</insert>
</mapper>
总结
第一种用时3000ms,第二种用时1500ms,第三种800ms,第三种效率最高
原因
在插入数时,减少连接数据库次数是提升效率的关键
坑点
在使用第三种方式时,需要注意如果数据太多,一次性插入会出现内存溢出的错误;因此我们在插入数据时,如果过多,则需要将数组拆分成多个数组,进行分批插入,工具类代码如下:
/**
* 分批插入-公共方法
* @param objects:数据集合
* @param subSize:单次插入的条数
*/
public static <E> List<List<E>> splitTo(List<E> objects, int subSize) {
//1.确定数据要分几次插入(根据总条数和每次插入条数)
List<List<E>> lists = new ArrayList();
int idCount = objects.size();
//插入次数(批量插入数据库次数)
int loopTimes = idCount / subSize;
if (loopTimes * subSize < idCount) {
loopTimes++;
}
//2.把每一次插入的数据放到双重集合里
for(int i = 0; i < loopTimes; ++i) {
int fromIndex = i * subSize;
int toIndex = (i + 1) * subSize;
lists.add(objects.subList(fromIndex, toIndex > idCount ? idCount : toIndex));
}
return lists;
}