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>