1.現象描述
(1)使用 Mybatis 在進行數據更新時,大部分時候update語句都需要通過動態SQL進行拼接。在其中,if標簽中經常會有 xxx !='' 這種判斷,若 number 類型的字段上傳遞的值為 0, 執行更新時會發現數據庫中的數據並沒有被更新成 0,這種異常現象不會報錯,所以容易被忽視。
<update id="update" parameterType="com.hrh.mybatis.bean.Person"> update tab_person <set> <if test="id != null"> id = #{id,jdbcType=BIGINT}, </if> <if test="name != null"> name= #{name,jdbcType=VARCHAR}, </if> <if test="age != null and age !=''" > age= #{age,jdbcType=BIGINT} </if> </set> where id = #{id,jdbcType=BIGINT} </update>
(2)在 if 標簽中有時會用到加條件的判斷,如 xxx != ‘x’,如果篩選條件中只有單個字符時,這樣拼接執行會報錯
### Error querying database. Cause: java.lang.NumberFormatException: For input string: "張三"
### Cause: java.lang.NumberFormatException: For input string: "張三"
<select id="selectByCondition" resultType="com.hrh.mybatis.bean.Person" parameterType="java.lang.String"> select <include refid="Base_Column_List"/> from tab_person where <if test="name != null and name !='a'"> name = #{name,jdbcType=VARCHAR} </if> </select>
2.原因探究
(1)Mybatis的表達式使用 OGNL 處理的,若對象是一個 number 類型,值為0時將被解析為 false,否則為 true,浮點型 0.00也是如此。所以問題1中的 <if test="age != null and age !=''" >當age為0時導致表達式的值為false,不進行SQL拼接,執行更新后數據庫中的數據不會被更新成0。
所以對於insert語句拼接也是一樣的,<if test="age != null and age !=''" >當age為0時導致表達式的值為false,不進行SQL拼接,導致參數和值傳遞不一致報錯
### Error updating database. Cause: java.sql.SQLException: Column count doesn't match value count at row 1
### The error may involve com.hrh.mybatis.mapper.PersonMapper.insertSelective-Inline
### The error occurred while setting parameters
### SQL: insert into tab_person ( id, name, age ) values ( ?, ? )
### Cause: java.sql.SQLException: Column count doesn't match value count at row 1
bad SQL grammar []; nested exception is java.sql.SQLException: Column count doesn't match value count at row 1
<insert id="insertSelective" parameterType="com.hrh.mybatis.bean.Person"> insert into tab_person <trim prefix="(" suffix=")" suffixOverrides="," > <if test="id != null"> id, </if> <if test="name != null"> name, </if> <if test="age != null"> age </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides="," > <if test="id != null">#{id,jdbcType=BIGINT}, </if> <if test="name != null"> #{name,jdbcType=VARCHAR}, </if> <if test="age != null and age !=''"> #{age,jdbcType=BIGINT} </if> </trim> </insert>
(2)單引號 '' 內如果為單個字符時,OGNL 將會識別為Java的char 類型,String類型與char 類型做運算時會報錯。
3.解決辦法
(1)number 類型的字段在進行拼接時只需要判斷 xxx!=null即可。
<update id="update" parameterType="com.hrh.mybatis.bean.Person"> update tab_person <set> <if test="id != null"> id = #{id,jdbcType=BIGINT}, </if> <if test="name != null"> name= #{name,jdbcType=VARCHAR}, </if> <if test="age != null" > age= #{age,jdbcType=BIGINT} </if> </set> where id = #{id,jdbcType=BIGINT} </update>
(2)第二種情況有多種解決辦法:
I.需要將單引號和雙引號調換即可。
<select id="selectByCondition" resultType="com.hrh.mybatis.bean.Person" parameterType="java.lang.String"> select <include refid="Base_Column_List"/> from tab_person where <if test='name != null and name !="a"'> name = #{name,jdbcType=VARCHAR} </if> </select>
II.添加toString() 進行類型轉換
<select id="selectByCondition" resultType="com.hrh.mybatis.bean.Person" parameterType="java.lang.String"> select <include refid="Base_Column_List"/> from tab_person where <if test="name != null and name !='a'.toString()"> name = #{name,jdbcType=VARCHAR} </if> </select>
III.添加轉義實體字符串引號
<select id="selectByCondition" resultType="com.hrh.mybatis.bean.Person" parameterType="java.lang.String"> select <include refid="Base_Column_List"/> from tab_person where <if test="name != null and name != "a""> name = #{name,jdbcType=VARCHAR} </if> </select>