对于需要同时插入大量表数据的需求,我们可以通过下述方式实现:
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的方式带来的性能差异极大,需要注意!