咱們先經過案例復現該類異常,測試項目地址: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 就能夠了。