MyBatis-Plus 自带的更新方法,都有对对象空值进行判空。只有不为空的字段才会进行数据更新。

本文介绍了MyBatis-Plus中如何通过注解@TableField解决对象更新时忽略空值的问题,展示了三种方法:未加注解、加注解和使用UpdateWrapper,以及相应的SQL执行变化。同时给出了TableField注解的详细说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原因

因为 MyBatis-Plus 自带的更新方法,都有对对象空值进行判空。只有不为空的字段才会进行数据更新。

解决方式

在实体类对应的字段上加注解@TableField(strategy=FieldStrategy.IGNORED),忽略null值的判断,例如:

@TableField(updateStrategy = FieldStrategy.IGNORED)
private String address;

示例:

1、未加注解(无法设入空值,见代码结果):

复制代码

//实体
private String address;


@Test
public void updateUserTest(){
    User user = new User();
    user.setId(1);
    user.setState((byte) 1);
    user.setAddress(null);
    userService.updateById(user);
}
​
//结果
==> Preparing: UPDATE user SET state=? WHERE id=? 
==> Parameters: 1(Byte), 1(Integer)
​

复制代码

 

2、加注解(可以设入空值,看代码结果)

复制代码

//实体
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String address;


@Test
public void updateUserTest(){
    User user = new User();
    user.setId(1);
    user.setState((byte) 1);
    user.setAddress(null);
    userService.updateById(user);
}
​
//结果
==>  Preparing: UPDATE user SET address=?, state=? WHERE id=? 
==> Parameters: null, 1(Byte), 1(Integer)

复制代码

 

3、直接使用 UpdateWrapper

复制代码

@Test
public void updateUserTest(){
    UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
    userUpdateWrapper.set("address", null);
    userUpdateWrapper.lambda().eq(User::getId, 1);
    userService.update(userUpdateWrapper);
}
​
//结果
==>  Preparing: UPDATE user SET address=? WHERE (id = ?) 
==> Parameters: null, 1(Integer)

复制代码

 

附上 MyBatis-Plus 表字段标识 注解类

复制代码

/**
 * 表字段标识
 *
 * @author hubin sjy tantan
 * @since 2016-09-09
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TableField {
​
    /**
     * 字段值(驼峰命名方式,该值可无)
     */
    String value() default "";
​
    /**
     * 是否为数据库表字段
     * 默认 true 存在,false 不存在
     */
    boolean exist() default true;
​
    /**
     * 字段 where 实体查询比较条件
     * 默认 `=` 等值
     */
    String condition() default "";
​
    /**
     * 字段 update set 部分注入, 该注解优于 el 注解使用
     * <p>
     * 例1:@TableField(.. , update="%s+1") 其中 %s 会填充为字段
     * 输出 SQL 为:update 表 set 字段=字段+1 where ...
     * <p>
     * 例2:@TableField(.. , update="now()") 使用数据库时间
     * 输出 SQL 为:update 表 set 字段=now() where ...
     */
    String update() default "";
​
    /**
     * 字段验证策略之 insert: 当insert操作时,该字段拼接insert语句时的策略
     * IGNORED: 直接拼接 insert into table_a(column) values (#{columnProperty});
     * NOT_NULL: insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
     * NOT_EMPTY: insert into table_a(<if test="columnProperty != null and columnProperty!=''">column</if>) values (<if test="columnProperty != null and columnProperty!=''">#{columnProperty}</if>)
     *
     * @since 3.1.2
     */
    FieldStrategy insertStrategy() default FieldStrategy.DEFAULT;
​
    /**
     * 字段验证策略之 update: 当更新操作时,该字段拼接set语句时的策略
     * IGNORED: 直接拼接 update table_a set column=#{columnProperty}, 属性为null/空string都会被set进去
     * NOT_NULL: update table_a set <if test="columnProperty != null">column=#{columnProperty}</if>
     * NOT_EMPTY: update table_a set <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
     *
     * @since 3.1.2
     */
    FieldStrategy updateStrategy() default FieldStrategy.DEFAULT;
​
    /**
     * 字段验证策略之 where: 表示该字段在拼接where条件时的策略
     * IGNORED: 直接拼接 column=#{columnProperty}
     * NOT_NULL: <if test="columnProperty != null">column=#{columnProperty}</if>
     * NOT_EMPTY: <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
     *
     * @since 3.1.2
     */
    FieldStrategy whereStrategy() default FieldStrategy.DEFAULT;
​
    /**
     * 字段自动填充策略
     */
    FieldFill fill() default FieldFill.DEFAULT;
​
    /**
     * 是否进行 select 查询
     * <p>大字段可设置为 false 不加入 select 查询范围</p>
     */
    boolean select() default true;
​
    /**
     * 是否保持使用全局的 Format 的值
     * <p> 只生效于 既设置了全局的 Format 也设置了上面 {@link #value()} 的值 </p>
     * <li> 如果是 false , 全局的 Format 不生效 </li>
     *
     * @since 3.1.1
     */
    boolean keepGlobalFormat() default false;
​
    /**
     * JDBC类型 (该默认值不代表会按照该值生效)
     * <p>
     * {@link ResultMapping#jdbcType} and {@link ParameterMapping#jdbcType}
     *
     * @since 3.1.2
     */
    JdbcType jdbcType() default JdbcType.UNDEFINED;
​
    /**
     * 类型处理器 (该默认值不代表会按照该值生效)
     * <p>
     * {@link ResultMapping#typeHandler} and {@link ParameterMapping#typeHandler}
     *
     * @since 3.1.2
     */
    Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
​
    /**
     * 指定小数点后保留的位数
     * <p>
     * {@link ParameterMapping#numericScale}
     *
     * @since 3.1.2
     */
    String numericScale() default "";
}
<think>好的,用户问的是MyBatis的listByMap怎么使用。首先,我需要回想一下MyBatis的基础知识。记得在MyBatis中,通常是通过Mapper接口定义方法,然后通过XML或注解来写SQL。但listByMap这个方法好像不是MyBatis自带的,可能是用户自己定义的,或者是通过MyBatis的动态SQL功能实现的。 接下来,我需要确定用户的具体需求。用户可能在使用MyBatis时,想根据传入的Map参数来动态查询数据,比如根据不同的条件筛选结果。这时候,可能需要在Mapper接口中定义一个方法,参数是Map,然后编写对应的动态SQL语句。 可能需要分步骤解释如何使用。首先,创建Mapper接口,定义方法,比如List<Entity> listByMap(Map<String, Object> params);。然后,在XML映射文件中编写对应的select语句,使用<where>标签和<if>标签来动态生成条件。例如,遍历Map中的键值对,将它们作为查询条件。 同时,还要考虑用户可能的错误,比如参数是否正确传递,Map中的键是否和数据字段对应,或者是否需要处理空值情况。此外,要提醒用户在使用动态SQL时,注意SQL注入的问题,尽量使用MyBatis提供的安全方式来处理参数。 另外,用户可能对Map的键如何对应到SQL中的字段有疑问,需要举例说明,比如Map里放的是{"name":"张三","age":20},那么SQL中的条件就是name=#{name} AND age=#{age}。如果用户希望灵活的条件,比如模糊查询或者范围查询,可能需要复杂的处理,比如在Map的值中使用特定的格式,或者在SQL中使用动态标签断。 还要提到,如果用户使用的是MyBatis-Plus,那么listByMap可能是内置的方法,可以直接调用,比如QueryWrapper的allEq方法,然后调用selectList。这种情况下,需要说明MyBatis-Plus和原生MyBatis的区别,避免用户混淆。 最后,总结使用步骤,强调关键点,比如确保Map的键与数据字段名一致,动态SQL的正确写法,以及如何处理可能为的条件。可能还需要给出一个完整的示例,帮助用户好地理解如何实现listByMap的功能。</think>以下是关于MyBatis中`listByMap`方法的详细使用说明: --- ### **1. 方法定义与作用** `listByMap`是**基于条件Map查询多条数据**的方法,常见于以下两种场景: 1. **原生MyBatis**:需手动实现,通过`Map`传递动态条件。 2. **MyBatis-Plus**:框架内置方法,直接调用即可(需继承`BaseMapper`)。 --- ### **2. 原生MyBatis实现** #### **步骤1:Mapper接口定义** ```java // UserMapper.java public interface UserMapper { List<User> listByMap(Map<String, Object> params); } ``` #### **步骤2:XML映射配置** ```xml <!-- UserMapper.xml --> <select id="listByMap" resultType="User"> SELECT * FROM user <where> <foreach collection="params" index="key" item="value" separator=" AND "> ${key} = #{value} </foreach> </where> </select> ``` **注意**:`${key}`直接替换字段名,需确保Map的键与数据库列名一致(存在SQL注入风险,建议用`<if>`标签过滤)。 --- ### **3. MyBatis-Plus实现** #### **前提条件** 实体类需添加`@TableName`注解: ```java @TableName("user") public class User { private Long id; private String name; private Integer age; } ``` #### **直接调用内置方法** ```java // 示例:查询name="张三"且age=20的用户 Map<String, Object> params = new HashMap<>(); params.put("name", "张三"); params.put("age", 20); List<User> userList = userMapper.selectByMap(params); ``` **规则**: - Map的键必须与数据字段名一致(默认驼峰转下划线)。 - 值为`null`时会拼接`IS NULL`条件。 --- ### **4. 复杂条件扩展** 若需要模糊查询、范围查询等,建议结合`QueryWrapper`: ```java QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.like(MapUtils.getString(params, "name"), "name") .between(MapUtils.getInteger(params, "minAge"), MapUtils.getInteger(params, "maxAge"), "age"); List<User> userList = userMapper.selectList(wrapper); ``` --- ### **5. 注意事项** | 场景 | 风险点 | 解决方案 | |-----------------------|---------------------------|----------------------------------| | 键名与数据库列名不匹配 | 查询条件失效 | 使用`@TableField`注解映射字段 | | Map值为 | 拼接`= NULL`可能不符合预期 | 动态过滤空值:`params.remove(null)` | | 原生MyBatis使用`${key}` | SQL注入风险 | 改用`<if>`标签过滤安全字段 | --- ### **总结** - **MyBatis-Plus**:优先使用`selectByMap()`,简单安全。 - **原生MyBatis**:需手动实现动态SQL,注意字段映射和SQL注入防护。 - **复杂查询**:结合`QueryWrapper`或`<if>/<choose>`标签灵活控制条件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值