Mysql数据库使用Mybatis批量更新的几种方式

       经过多次项目经历,总结几种更新方式的对比,作以下总结。

待更新对象 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尽可能少,更新条件字段最好有索引(主键即可)

猜你喜欢

转载自blog.csdn.net/csdnbeyoung/article/details/106258611