关于Mybatis查询中列表里的对象为null的问题解决

博客指出mapper.xml中select执行语句返回的list的size大于0,但list里对象为null的问题。目前尚未明确问题原理,解决办法是修改select语句中resultType为resultMap,值设为fileConfig。

1. 问题修正之前

mapper.xml

<resultMap id="fileConfig" type="demo.model.dto.FileConfigModel">
    <id column="i_id" property="id"/>
    <result column="c_app_id" property="bizCode"/>
    <result column="c_desc" property="bizDesc"/>
    <result column="c_suffix" property="fileFormat"/>
    <result column="i_max_size" property="fileMaxSize"/>
    <result column="c_time" property="createTime"/>
    <result column="c_update_time" property="updateTime"/>
</resultMap>

<select id="getFileConfig" parameterType="demo.model.req.GetFileConfigReq"
        resultType="demo.model.dto.FileConfigModel">
    select c_app_id,c_desc,c_suffix,i_max_size
    from file_conf_apply where 1=1
    <if test="bizCode != null and bizCode != ''">
        and c_app_id LIKE CONCAT(CONCAT('%',#{bizCode}),'%')
    </if>
    <if test="bizDesc != null and bizDesc != ''">
        and c_desc LIKE CONCAT(CONCAT('%',#{bizDesc}),'%')
    </if>
     limit #{fromIndex},#{pageCount}
</select>

出现的问题是,select执行语句返回的list的size大于0,但是,list里面的对象为null。

 

2. 问题的解决

目前原理还没了解清楚,如果看到的朋友有知道的话,可以在博文下面留言。问题的解决办法是:

修改select语句中resultType。将resultType修改为resultMap,值为fileConfig。修改后的代码为:

<select id="getFileConfig" parameterType="demo.model.req.GetFileConfigReq"
        resultMap="fileConfig">
    select c_app_id,c_desc,c_suffix,i_max_size
    from file_conf_apply where 1=1
    <if test="bizCode != null and bizCode != ''">
        and c_app_id LIKE CONCAT(CONCAT('%',#{bizCode}),'%')
    </if>
    <if test="bizDesc != null and bizDesc != ''">
        and c_desc LIKE CONCAT(CONCAT('%',#{bizDesc}),'%')
    </if>
     limit #{fromIndex},#{pageCount}
</select>

 

 

 

<think>根据用户的问题,用户在使用MyBatis的if标签时,遇到了判断对象是否为null问题。结合用户提供的引用内容,特别是引用[3]中提到的情况,当传入多个对象参数时,需要在test表达式中使用带别名的属性路径。同时,引用[1]展示了基本的使用方式,即使用`属性名 != null`来判断。 用户可能遇到的情况是: 1. 在if标签的test表达式中直接使用对象的属性,而没有指定参数别名(当有多个参数时)。 2. 对象属性本身为基本类型(如int),无法判断null(因为基本类型不能为null,所以可能不需要判断null,但需要判断是否为0等)。 3. 字符串判断空字符串和null的情况。 解决方案如下: ### 一、问题分析 在MyBatis的XML映射文件中,使用`<if>`标签进行条件判断时,如果传入的参数是一个对象,可以直接使用对象的属性名进行判断(如`test="name != null"`)。但是,如果传入多个对象参数,则必须使用`@Param`注解为每个参数指定别名,然后在test表达式中使用别名.属性名(如`test="obj1.name != null"`)[^3]。 ### 二、解决方法 #### 1. 单个对象参数 如果方法只有一个对象参数,可以直接使用属性名: ```xml <select id="findAll" resultMap="emp" parameterType="Emp2"> select * from tbl_employee <where> <if test="empId != null"> <!-- 正确:直接使用属性名 --> and id = #{empId} </if> <if test="empLastName != null"> and last_name = #{empLastName} </if> </where> </select> ``` #### 2. 多个对象参数 如果方法有多个对象参数,需要使用`@Param`为每个参数命名,并在test表达式中使用别名.属性名: ```java // 接口方法 ObjectX getByNameAndVersion(@Param("obj1") Object1 obj1, @Param("obj2") Object2 obj2); ``` ```xml <select id="getByNameAndVersion" resultMap="baseMap"> select * from xxx <where> <if test="obj1.name != null"> <!-- 使用别名.属性名 --> name=#{obj1.name} </if> <if test="obj2.version != null"> and version=#{obj2.version} </if> </where> </select> ``` #### 3. 判断空字符串 如果需要判断字符串不为空且不为空字符串,可以这样写: ```xml <if test="str != null and str != ''"> and name = #{str} </if> ``` #### 4. 注意字符比较 在test表达式中,字符串比较时,避免使用单引号包裹单个字符的字符串,否则会被识别为char类型,导致比较失败[^2]: ```xml <!-- 错误:'A'会被识别为char,与String类型比较会返回false --> <if test="str != null and str == 'A'"> ... </if> <!-- 正确:使用双引号 --> <if test="str != null and str == "A""> ... </if> <!-- 或者使用转义 --> <if test='str != null and str == "A"'> ... </if> ``` #### 5. 数值类型判断 对于基本数据类型(如int、double等),由于它们不能为null,所以不需要判断null,但可能需要判断0的情况。例如: ```xml <if test="age != 0"> <!-- 基本类型int,不能为null,所以判断是否为0 --> and age = #{age} </if> ``` ### 三、常见错误 1. **未使用别名**:当有多个参数时,直接使用属性名而没有别名前缀,会导致找不到属性。 2. **字符比较错误**:使用单引号包裹单个字符的字符串,导致比较失败。 3. **转义问题**:在test表达式中使用`<`、`<=`等符号时,需要转义,因为XML中这些符号是保留字符。可以使用`lt`、`le`等替代,或者使用CDATA包裹[^4]: ```xml <if test="age < 18"> <!-- 使用转义 --> and age < 18 </if> <!-- 或者 --> <if test="age < 18"> <!-- 这样写会报错,因为XML解析器会认为<是标签的开始 --> <!-- 正确做法是使用转义或CDATA --> <if test="age lt 18"> <!-- 使用lt --> and age < 18 </if> ``` ### 四、完整示例 假设有一个查询方法,传入两个对象参数(User和Department),查询用户信息: ```java public interface UserMapper { List<User> selectByCondition(@Param("user") User user, @Param("dept") Department dept); } ``` XML映射文件: ```xml <select id="selectByCondition" resultType="User"> SELECT * FROM user <where> <if test="user.name != null and user.name != ''"> AND name = #{user.name} </if> <if test="user.age != 0"> <!-- 假设age是int类型 --> AND age = #{user.age} </if> <if test="dept.id != null"> AND dept_id = #{dept.id} </if> <if test="dept.name != null and dept.name == "IT""> AND dept_name = 'IT' </if> </where> </select> ``` ### 五、总结 | 问题类型 | 解决方案 | |----------|----------| | 单个对象参数 | 直接使用属性名,如 `test="prop != null"` | | 多个对象参数 | 使用别名.属性名,如 `test="obj.prop != null"` | | 字符串判断 | 同时判断null和空字符串,使用双引号包裹字符串 | | 字符比较 | 避免单引号包裹单个字符,使用双引号或转义 | | 数值判断 | 基本类型判断0,包装类型判断null | | 特殊符号 | 使用转义(如`<`)或替代词(`lt`, `le`) | **最佳实践**: - 使用包装类型(如Integer)代替基本类型,以便能够判断null。 - 多个参数时务必使用`@Param`注解。 - 字符串比较使用双引号。 §§相关问题§§ 1. MyBatis中如何同时判断null和空字符串? 2. MyBatis的if标签中如何使用逻辑运算符(and, or)? 3. MyBatis传入多个参数时如何避免参数别名冲突? 4. MyBatis中如何避免SQL注入问题? [^1]: 引用[1]展示了if标签的基本使用。 [^2]: 引用[2]提醒了单引号在字符串比较中的问题。 [^3]: 引用[3]说明了多参数情况下需要使用别名。 [^4]: 引用[4]指出在test属性中不能直接使用`<`等符号,需要转义或使用替代词。</think>### MyBatis `<if>` 标签判断对象null问题解决方案 #### 问题分析 在 MyBatis 中使用 `<if>` 标签判断对象是否为 null 时,常见以下问题: 1. **多参数场景未使用别名**:当方法有多个对象参数时,直接使用属性名会导致判断失败[^3] 2. **字符比较错误**:单引号包裹的单个字符会被识别为 char 类型,导致与 String 比较失败[^2] 3. **特殊符号未转义**:`<`, `>` 等符号在 XML 中需特殊处理[^4] 4. **空字符串判断遗漏**:未同时判断 null 和空字符串 #### 解决方案 ##### 1. 单对象参数场景 ```xml <select id="findUser" resultType="User"> SELECT * FROM user <where> <if test="name != null"> <!-- 直接使用属性名 --> AND name = #{name} </if> <if test="age != null"> AND age = #{age} </if> </where> </select> ``` ##### 2. 多对象参数场景(必须使用 `@Param` 别名) ```java // Mapper 接口方法 List<User> findUsers( @Param("filter") UserFilter filter, // 使用@Param定义别名 @Param("page") PageParam page ); ``` ```xml <select id="findUsers" resultType="User"> SELECT * FROM user <where> <if test="filter.name != null"> <!-- 使用别名.属性名 --> AND name = #{filter.name} </if> <if test="page.size != null"> LIMIT #{page.size} </if> </where> </select> ``` ##### 3. 字符串判断(避免单引号陷阱) ```xml <!-- 错误示例:单引号导致'A'被识别为char --> <if test="status == 'A'">...</if> <!-- 正确方案1:双引号包裹 --> <if test='status == "A"'>...</if> <!-- 正确方案2:转义单引号 --> <if test="status == 'A'">...</if> ``` ##### 4. 空字符串和 null 联合判断 ```xml <if test="name != null and name != ''"> AND name = #{name} </if> ``` ##### 5. 特殊符号转义方案 ```xml <!-- 使用转义字符 --> <if test="age < 18"> <!-- 等价于 age < 18 --> AND category = 'child' </if> <!-- 使用替代关键字 --> <if test="age lt 18"> <!-- lt 表示 < --> AND category = 'child' </if> ``` #### 完整示例 ```java // Mapper接口 public interface UserMapper { List<User> selectByFilter( @Param("user") User user, @Param("dept") Department dept ); } ``` ```xml <select id="selectByFilter" resultType="User"> SELECT * FROM users <where> <!-- 多参数需使用别名 --> <if test="user.name != null and user.name != ''"> AND name = #{user.name} </if> <!-- 字符串双引号比较 --> <if test='dept.code == "IT"'> AND department_code = 'IT' </if> <!-- 特殊符号转义 --> <if test="user.age >= 18"> <!-- 等价于 >= --> AND is_adult = 1 </if> </where> </select> ``` #### 关键注意事项 1. **别名必要性**:多参数时必须通过 `@Param` 指定别名,否则无法识别对象属性[^3] 2. **字符串比较**:始终使用双引号包裹字符串值,避免单字符识别问题[^2] 3. **XML 转义**:`<` 和 `>` 必须使用 `<` 和 `>` 或关键字 `lt`/`gt`[^4] 4. **空值处理**:同时检查 `null` 和空字符串 (`''`) 确保逻辑完整 5. **基本类型陷阱**:基本数据类型(如 int)永远不为 null,需用包装类(Integer) #### 符号对照表 | 运算符 | XML 转义 | 替代关键字 | 示例 | |--------|----------|------------|------| | `<` | `<` | `lt` | `age < 18` 或 `age lt 18` | | `>` | `>` | `gt` | `score > 90` 或 `score gt 90` | | `<=` | `<=` | `lte` | `age <= 18` 或 `age lte 18` | | `>=` | `>=` | `gte` | `score >= 60` 或 `score gte 60` | [^1]: 基础 if 标签使用[^1] [^2]: 单引号字符比较问题[^2] [^3]: 多对象参数处理[^3] [^4]: 特殊符号转义方案[^4]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值