MyBatis中的批量插入
<insert id="batchInsert" >
insert into table_name
(aa, bb, cc, dd)
values
<foreach collection="list" item="item" separator=",">
xxxxxxxxx
</foreach>
</insert>
批量插入都会这样去写。他对应的SQL应该是
insert into table_name
(aa, bb, cc, dd) values(1,1,1,1),(2,2,2,2),(3,3,3,3)
原因就是:他可以将许多小操作变成一个大操作 最简单的就是减少网络IO.并且将检查索引更新和一致性检查放到最后。
问题
当表列数在20+ 插入的list 5000+的时候 整个过程很长 大概花了10分钟。这种情况应该是不被允许的。
原因
他的默认执行机器是Simple,也就是会为每一个语句创建一个新preparedStatement对象。对于这种foreach 没办法cache。然后由于value太长假设几千个 那他的PrepareStatement就会很长。然后存在占位符和参数的mapping这个也会很耗时。
查阅Mybatis官网和资料 发现大概是在20-50这个样子的values是性能比较高的
所以可以采用map reduce的思想。N个拆分成N/50次循环。但是也会带来个问题。就是会链接多次。
Mybatis官方建议
http://www.mybatis.org/mybatis-dynamic-sql/docs/insert.html
try(SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) {
SimpleTableMapper mapper = session.getMapper(SimpleTableMapper.class);
List<SimpleTableRecord> records = getRecordsToInsert(); // not shown
BatchInsert<SimpleTableRecord> batchInsert = insert(records)
.into(simpleTable)
.map(id).toProperty("id")
.map(firstName).toProperty("firstName")
.map(lastName).toProperty("lastName")
.map(birthDate).toProperty("birthDate")
.map(employed).toProperty("employed")
.map(occupation).toProperty("occupation")
.build()
.render(RenderingStrategies.MYBATIS3);
batchInsert.insertStatements().forEach(mapper::insert);
session.commit();
}