通过forEach动态SQL方式
实现原理
forEach批量插入的原理是直接通过forEach动态标签,根据传过来的参数数量动态生成一个很长的SQL语句。一个语句就是一次批量插入。
语句形如:
insert into user (username, age) values
('张三', 10),
('李四', 10),
('王五', 10),
('赵六', 10),
('盖聂', 9000)
# 上面的语句一次会插入5条数据
我们需要做的就是生成此语句就可以了。
具体做法
Mapper接口
int batchInsertUser(List<User> userList);
Mapper映射文件
<!-- collection:为遍历集合的类型,item 为每次遍历的对象 ,separator 为每次遍历后自动为你添加的代码 -->
<insert id="batchInsertUser">
insert into user (username, age) values
<forEach collection="list" item="user" separator=",">
(#{user.username}, #{user.age})
</forEach>
</insert>
通过Executor.BATCH的方式
实现原理
这种批量插入在底层的Mapper接口和Mapper映射文件中,都只是一个普通插入单条数据的写法。它通过在上层获取SqlSession时,指定执行类型是批量ExcecutorType.BATCH的方式,实现每次执行完单条插入以后并没有真正写入数据库,只有当调用sqlSession.flushStatement()时,才会将这一批数据一次性写入数据库,从而实现批量操作。
使用步骤
-
获取SqlSession时指定执行类型为批量
// 获取一个批量执行的sqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH,true);
- Mapper接口和Mapper映射文件中只需按照单条插入去写方法和SQL语句即可
Mapper接口
int insertUser(User user);
XML映射文件
<insert id="insertUser">
insert into user (nick_name, status, createtime)
values
(#{nickName},#{status},#{createtime})
</insert>
-
空置批量的大小,在够一批数据时,调用
sqlSession.flushStatement()
去整体往数据库写一次int batchSize = 100; int count = 0; List<int []> resultList = new ArrayList<>(); for(User user : userList) { // ExecutorType.Batch方式这里返回的不是影响的条数,具体获取方法参见下面代码 mapper.insertUser(user); count++; if(count % batchSize == 0) { resultList.addAll(sqlSession.flushStatements().get(0).getUpdateCounts()); } } resultList.addAll(sqlSession.flushStatements().get(0).getUpdateCounts());
-
获取影响的条数
这种方式获取影响条数没有那么直接,需要去API返回的BatchResult对象中读取updateCounts方法才能拿到。
int rows = 0; for(int[] ins: resultList) { for(int in: ins) { rows += in; } } System.out.println("批量插入成功,响应的行数:" + rows);