有很多时候需要将一组数据进行入库,比如一个实体多个图片、某个文件夹下面的资源需要全部移到另外一个文件夹下。当数量比较小的时候,采用代码层for循环单条插入和数据库层批量插入的性能可能没有太大区别。不过当量比较大的时候数据库批量插入的性能就明显优越于代码层的for循环了。
原理很简单。代码层的for循环会循环几次就和数据库交互几次,占用连接池不说,还耗费了很多时间在交互上。而数据库层批量插入就只交互一次,占用资源极少,交互时间极短。当数据量达到一定程度,你会发现你爽死了~~~
接下来就简单分析一下两种方式。(以insert为例):
1.将for循环放在代码层:
private void addImagesOfObject(String imageList, Integer objId){
if(StringUtils.isNotBlank(imageList)){
String[] imgIdList = imageList.split(",");
ObjectImagesModel imageModel = new ObjectImagesModel();
imageModel.setObjectId(objId);
for(String imgId:imgIdList){
if(StringUtils.isNumeric(imgId)){
imageModel.setImageid(Integer.valueOf(imgId));
int result = imagesService.insertImage(imageModel);
if(result<1){
Object[] logArg = new Object[]{objId, imgId};
logger.info("adding object' images occurs wrong. objId={};imageId={},", logArg);
}
}
}
}
}
这种方式是应付需要得到记录主键,根据主键记录日志(比如性能日志,业务日志)。除此之外没有什么好处
2.将for循环放在数据库层即Mapper中
<span style="white-space:pre"> </span><insert id="insertBatch" parameterType="java.util.List">
insert into t_obj_images(obj_id,image_id,image_url,image_descr) values
<foreach collection="list" item="item" index="index" separator=",">
<trim prefix="(" suffix=")" suffixOverrides=",">
#{item.objId},#{item.imageId},#{item.imageUrl},#{item.imageDescr}
</trim>
</foreach>
</insert>
这种方式性能优越,数据量越大比上述方法的效率倍数越高。不足的地方是返回插入的记录组件比较困难。上面配置返回的是成功执行后插入的记录数。后续有时间研究怎么返回插入记录的主键列表
对于更新和删除的批量操作来说主要有两种形式:
1.条件判断,符合条件的记录有多条,这样可以进行批量的更新和删除,由于好理解,就不上代码了。
2.in语句(其实也算是条件判断),主要用在主键范围上,使用foreach循环即可,也就不上代码了。
~~待续