经过多次项目经历,总结几种更新方式的对比,作以下总结。
待更新对象 User 。实际项目中,可能会批量更新一组数据
第一种:在程序中通过for循环,循环提交,这种方式就无所谓更新的数据是怎样的,多次调用mapper提交数据,与数据库交互多次,性能差,实现简单。如果更新大批量数据不建议使用这种方式
例子代码实现如下:
java代码:
for(User user:list){
userMapper.update(user);
}
XML代码:
<update id="update" parameterType="com.enjoy.mybatis.entity.User">
update user
<set>
<if test="username != null">
username = #{username,jdbcType=VARCHAR},
</if>
<if test="password != null">
password = #{password,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=TIMESTAMP},
</if>
<if test="remark != null">
remark = #{remark,jdbcType=VARCHAR},
</if>
<if test="roleLevel != null">
role_level = #{roleLevel,jdbcType=INTEGER},
</if>
<if test="deleteFlag != null">
delete_flag = #{delete_flag,jdbcType=INTEGER},
</if>
</set>
<where>
id = #{id,jdbcType=INTEGER}
</where>
</update>
第二种:mybatis的foreach标签,批量提交多条sql,这种方式只与数据库交互一次,一次提交了多条数据,将批量处理的工作交给mysql,但是mysql实际执行的还是多条sql,如果数据量过大,性能还是很差,如果更新的条件字段上没有索引,数据库数据量过大的情况会极大影响性能,所以尽量保证以主键更新
例子代码实现如下:
java代码:
List<User> list = userMapper.selectAll();
for (User user:list){
//逻辑处理
}
//提交list
userMapper.batchUpdate(list);
xml代码:
<update id="batchUpdate" parameterType="java.util.List" >
<foreach collection="list" item="item" index="index" open="" close="" separator=";">
update user
<set>
<if test="item.username != null and item.username != '' ">
username = #{item.username,jdbcType=VARCHAR},
</if>
<if test="item.password != null and item.password != '' ">
password = #{item.password,jdbcType=VARCHAR},
</if>
<if test="item.remark != null and item.remark != '' ">
remark = #{item.remark,jdbcType=VARCHAR},
</if>
<if test="item.updateTime != null ">
update_time = #{item.updateTime,jdbcType=TIMESTAMP},
</if>
</set>
<where>
<if test="item.id != null">
id = #{item.id,jdbcType=INTEGER}
</if>
</where>
</foreach>
</update>
第三种:如果要更新的字段可以确定,而且更新的内容都是一样的,比如将用户的级别更新为会员,则更新时间和级别这两个字段是确定的,更新的值也能确定,则将这些数据拼接成一条sql来进行更新
例子代码实现如下:
java代码:
List<Integer> ids = new ArrayList<>();
List<User> userList = userMapper.selectAll();
for (User user:list){
ids.add(user.getId());
}
user.setIds(ids);
user.setLevel(2);
user.setLevel(new Date());
//提交list
userMapper.updateByUser(user);
XML代码:
<update id="updateByUser" parameterType="com.xxx.xxx.User" >
update user
<set>
<if test="level != null ">
level = #{level,jdbcType=BIGINT},
</if>
<if test="updateTime != null ">
update_time = #{updateTime ,jdbcType=TIMESTAMP},
</if>
</set>
<where>
id in
<foreach collection="ids" item="item" index="index"
open="(" close=")" separator=",">
#{item,jdbcType=INTEGER}
</foreach>
</where>
第四种:更新多个字段,每个字段的值都是不确定的(更新字段个数要确定),也按照第三种的思路,拼装传1条sql,同时使用mysql的case when then else end 语法;目前来看这种方式的性能是最高的,但是实现起来有点复杂。
例子代码实现如下:
java代码:
List<User> list = userMapper.selectAll();
for (User user:list){
//逻辑处理
}
//提交list
userMapper.batchUpdate(list);
xml代码:
<update id="batchUpdate" parameterType="java.util.List">
update user
<trim prefix="set" suffixOverrides=",">
<trim prefix="remark =( case" suffix="else '' end ),">
<foreach collection="list" item="item" index="index">
<if test="item.remark != null and item.remark != '' ">
when id = #{item.id} then #{item.remark}
</if>
</foreach>
</trim>
<trim prefix="username = ( case" suffix="else '' end ),">
<foreach collection="list" item="item" index="index">
<if test="item.username != null and item.username != '' ">
when id = #{item.id} then #{item.username}
</if>
</foreach>
</trim>
<trim prefix="password = ( case" suffix="else '' end ),">
<foreach collection="list" item="item" index="index">
<if test="item.password != null and item.password != '' ">
when id = #{item.id} then #{item.password}
</if>
</foreach>
</trim>
</trim>
where id in
<foreach collection="list" index="index" item="item" separator="," open="(" close=")">
#{item.id,jdbcType=INTEGER}
</foreach>
</update>
其中 else '' 可以不写
if标签的判断也可以不写,因为是确定要更新的字段
这里简单写下 mysql 的case when then else end 语法:
update user set level = (
case 【colum】
when 【value】then 【result】
when 【value】then 【result】
else 【default】
end
),
...
update_time = (
case 【colum】
when 【value】then 【result】
when 【value】then 【result】
else 【default】
end
)
where 【colum】 in (【value】【value】);
按照这个格式,在xml文件里拼接sql就可以实现高性能的批量更新
【总结】:实现批量更新希望与数据库交互尽可能少,而且执行的sql尽可能少,更新条件字段最好有索引(主键即可)