对于需要同时插入大量表数据的需求,我们可以通过下述方式实现:
for(Commit commit: commitList){
commitDao.insertCommit(commit);
}
但我们很快就会发现系统效率低下。插入2000条数据大概花了4mins。
在思考如何提速的过程中,首先想到的就是如何进行batchInsert!
commitDao.batchInsertCommit(commitList);
那怎么做呢?其实很简单,但需要注意细节。
常规的,我们需要写好dao,mapper以及xml,demo分别如下:
public void batchInsertCommit(List<Commit> commitList) {
commitMapper.batchInsertCommit(commitList);
}
void batchInsertCommit(@Param("commitList") List<Commit> commitList);
<insert id="batchInsertCommit" parameterType="List">
INSERT INTO commit
(commit_id,
message,
developer,
commit_time,
repo_uuid,
developer_email,
self_index,
parent_commit)
VALUES
<foreach collection="commitList" item="c" separator=",">
(
#{c.commit_id},
#{c.message},
#{c.developer},
#{c.commit_time},
#{c.repo_uuid},
#{c.developer_email},
#{c.self_index},
#{c.parent_commit})
</foreach>
</insert>
上述代码是正常可以工作的,但是在实现这个版本之前,我犯了一些错误。
系统报错如下:
"msg": "failure nested exception is org.apache.ibatis.binding.BindingException: Parameter 'uuid' not found. Available parameters are [commitList, param1]",
"data": null }
原以为是在主键自增的情况下,可能不支持多条value的添加。但通过实际的sql证明了这一点是可行的。
需要注意的点如下:
- 关于批量insert,demo如上。必须在values内部,通过集合的item指定value,比如c.commit_id,没有引用则会报错找不到commit_id。
- 另一方面是,在mapper.java中也一定要对方法参数进行@Param(“paramName”)的修饰,不然也会显示找不到该参数。
性能测试:
测试方法
long stime = System.currentTimeMillis();
// insesrt 操作
long etime = System.currentTimeMillis();
发现single insert分别耗时: 103670,106130,100602 ms
batch insert耗时: 3557, 1517,1047,1814,1551,1235 ms
性能得到极大提升!
总结:
系统的性能瓶颈很大情况下不取决于硬件,使用sql的方式带来的性能差异极大,需要注意!