MyBatis 数值类型 where 条件配置的坑

本文通过一个具体的案例,展示了在MyBatis中使用Byte类型字段时,错误地将其作为字符串进行判断导致的异常。分析了源码发现,问题出在OGNL表达式的处理上,当比较Byte 0和空字符串时,OGNL认为两者相同。因此,对于数值类型的参数,在配置where条件时不应使用字符串判断,只需判断sex != null。

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

更多文章参考我的笔记:https://www.yuque.com/yinjianwei/vyrvkf

 

复现异常

我们先通过案例复现该类异常,测试项目地址:https://gitee.com/yin_jw/demo/tree/master/mybatis-demo/springboot-mybatis-demo,StudentMapper.xml 中根据条件获取学生信息的 SQL 配置如下所示。

<!-- 根据条件获取学生信息-->
<select id="listByConditions" parameterType="studentQuery" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from t_student
    <where>
        <if test="ids != null and ids.size() > 0">
            AND id IN
            <foreach collection="ids" item="item" open="(" close=")" separator=",">
                #{item}
            </foreach>
        </if>
        <if test="name != null and name != ''">
            AND name LIKE CONCAT('%', #{name}, '%')
        </if>
        <if test="sex != null and sex != ''">
            AND sex = #{sex}
        </if>
        <if test="selfcardNo != null">
            AND selfcard_no = #{selfcardNo}
        </if>
    </where>
</select>

该配置问题出在 <if test="sex != null and sex != ''"> 这段代码,sex 在传入的参数中是 Byte 类型,属于数值类型,而 sex != '' 适用于字符串类型判断,我们误将数值类型当成字符串类型配置了。

当我们错误的配置了 sex 字段的判断条件,传入 sex = 0 时,sex != '' 会返回 false,传入 sex = 1 时,sex != '' 会返回 true,同样是传入数字,为什么会出现两种不同的结果呢? 

sex = 0 的执行效果如下图所示:

sex = 1 的执行效果如下图所示:

sex = 0 的执行返回内容明显不是我们需要的结果,下面我们通过源码分析来解开这个谜题。

分析源码 

通过源码分析篇中的“MyBatis 源码篇-SQL 执行的流程”章节,我们知道 MyBatis 执行 SQL 最终都会交给 Executor 类执行。 

前面的调试步骤省略,直接进入 CacheExecutor 类的 query 方法。

猜测 MyBatis 根据参数和映射配置文件生成 boundSql 的时候,出现了一些问题。我们一路往下 DEBUG,发现问题出在 MyBatis 对 OGNL 表达式处理上面。 

org.apache.ibatis.ognl.OgnlOps#compareWithConversion(Object v1, Object v2) 该方法在比较 (Byte)0 和 "" 时,返回的是 true,也就是该方法认为两者是相同的,执行结果如下图所示。

所以,sex = 0 的条件没有出现在生成的 SQL 中。

那么当 sex = 1 的时候,compareWithConversion(Object v1, Object v2) 方法的执行结果是怎样的呢?

修改参数,调试测试接口,执行结果如下图所示:

compareWithConversion(Object v1, Object v2) 方法返回的结果是 false,其实该问题的本质是,org.apache.ibatis.ognl.OgnlOps#doubleValue(Object value) 方法当 value 是空字符串时返回 0.0D。

结论 

对于数值类型的参数,在配置 where 条件的时候要注意,不能把它当成字符串类型判断,数值型只需要判断 sex != null 就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值