MyBatis 數值類型 where 條件配置的坑

復現異常

咱們先經過案例復現該類異常,測試項目地址:https://gitee.com/yin_jw/demo/tree/master/mybatis-demo/springboot-mybatis-demo,StudentMapper.xml 中根據條件獲取學生信息的 SQL 配置以下所示。git

<!-- 根據條件獲取學生信息-->
<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 != '' 適用於字符串類型判斷,咱們誤將數值類型當成字符串類型配置了。spring

當咱們錯誤的配置了 sex 字段的判斷條件,傳入 sex = 0 時,sex != '' 會返回 false,傳入 sex = 1 時,sex != '' 會返回 true,一樣是傳入數字,爲何會出現兩種不一樣的結果呢? apache

sex = 0 的執行效果以下圖所示:springboot

sex = 1 的執行效果以下圖所示:mybatis

sex = 0 的執行返回內容明顯不是咱們須要的結果,下面咱們經過源碼分析來解開這個謎題。app

分析源碼 

經過源碼分析篇中的「MyBatis 源碼篇-SQL 執行的流程」章節,咱們知道 MyBatis 執行 SQL 最終都會交給 Executor 類執行。 源碼分析

前面的調試步驟省略,直接進入 CacheExecutor 類的 query 方法。測試

猜想 MyBatis 根據參數和映射配置文件生成 boundSql 的時候,出現了一些問題。咱們一路往下 DEBUG,發現問題出在 MyBatis 對 OGNL 表達式處理上面。 spa

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 就能夠了。

相關文章
相關標籤/搜索