Spring Boot + MyBatis 动态字段更新方法

在Spring Boot和MyBatis中,实现动态更新不固定字段的步骤如下:

方法一:使用MyBatis动态SQL(适合字段允许为null的场景)

  1. 定义实体类

    包含所有可能被更新的字段。

  2. Mapper接口

    定义更新方法,参数为实体对象:

    java

    复制代码
    void updateUserSelective(User user);
  3. XML映射文件

    使用<set><if>动态生成SQL:

    xml

    复制代码
    <update id="updateUserSelective" parameterType="User">
        UPDATE user
        <set>
            <if test="name != null">name = #{name},</if>
            <if test="age != null">age = #{age},</if>
            <if test="address != null">address = #{address},</if>
            <if test="phone != null">phone = #{phone},</if>
        </set>
        WHERE id = #{id}
    </update>

注意 :此方法无法将字段更新为null,因为参数为null时条件不成立。


方法二:使用Map和字段过滤(支持字段更新为null)

  1. Service层过滤字段

    在Service中定义允许更新的字段,并过滤请求参数:

    java

    复制代码
    public void updateUser(Long id, Map<String, Object> updates) {
        Set<String> allowedFields = Set.of("name", "age", "address", "phone");
        updates.keySet().retainAll(allowedFields); // 过滤非法字段
        userMapper.updateUserSelective(id, updates);
    }
  2. Mapper接口

    使用Map接收动态字段:

    java

    复制代码
    void updateUserSelective(@Param("id") Long id, @Param("updates") Map<String, Object> updates);
  3. XML映射文件

    动态生成更新语句:

    xml

    复制代码
    <update id="updateUserSelective">
        UPDATE user
        <set>
            <foreach collection="updates" index="key" item="value" separator=",">
                ${key} = #{value}
            </foreach>
        </set>
        WHERE id = #{id}
    </update>

注意 :使用${key}存在SQL注入风险,需在Service层严格过滤字段名。


方法三:使用@UpdateProvider(灵活且安全)

  1. 定义SQL提供类

    动态构建安全SQL:

    java

    复制代码
    public class UserSqlProvider {
        public String updateSelective(Map<String, Object> params) {
            Long id = (Long) params.get("id");
            Map<String, Object> updates = (Map<String, Object>) params.get("updates");
            Set<String> allowedFields = Set.of("name", "age", "address", "phone");
            
            StringBuilder sql = new StringBuilder("UPDATE user SET ");
            allowedFields.forEach(field -> {
                if (updates.containsKey(field)) {
                    sql.append(field).append(" = #{updates.").append(field).append("}, ");
                }
            });
            sql.setLength(sql.length() - 2); // 移除末尾逗号
            sql.append(" WHERE id = #{id}");
            return sql.toString();
        }
    }
  2. Mapper接口

    使用@UpdateProvider注解:

    java

    复制代码
    @UpdateProvider(type = UserSqlProvider.class, method = "updateSelective")
    void updateUserSelective(@Param("id") Long id, @Param("updates") Map<String, Object> updates);

优点:避免SQL注入,动态生成安全语句。


总结

  • 方法一 适合简单场景,字段无需设置为null

  • 方法二灵活,需严格过滤字段。

  • 方法三推荐用于生产环境,安全且维护性强。

根据需求选择合适方案,确保字段更新的灵活性和安全性。

相关推荐
nice_lcj520几秒前
排序(4)-归并排序专题——归并排序的分治美学
java·数据结构·算法·排序算法
我登哥MVP3 分钟前
SpringCloud 核心组件解析:服务调用和负载均衡
java·spring boot·后端·spring·spring cloud·java-ee·负载均衡
插件开发4 分钟前
英伟达cuda程序通用性关键 geforce 20xx代到最新版 在20xx上编译的c++程序可以通用吗?
java·c++·人工智能
JackSparrow4145 分钟前
彻底理解Java NIO(三)Java实现 I/O多路复用+Reactor模式及开源框架代码解读
java·c语言·开发语言·后端·nio·reactor模式
程序员黑豆6 分钟前
AI全栈开发 - Java:数据类型
java·前端
曹牧7 分钟前
Java:Xml中的大、小于
java·开发语言
zavoryn9 分钟前
Jackson 序列化踩坑:LocalDateTime、Long 精度丢失和 boolean isXxx 字段
java·开发语言·后端
江华森9 分钟前
Tomcat 10 实战部署指南:从零到生产级 Web 容器
java·前端·tomcat
曹牧9 分钟前
Java:XML转义
xml·java·开发语言
心之伊始12 分钟前
Dubbo 3 Consumer 调用链路源码分析:从 Proxy 到 Cluster、Directory、Router、LoadBalance
java·微服务·dubbo·源码分析·服务治理