MyBatis 的 `<if test="">` 语句里面使用反单引号的问题

时间:2022-07-26
本文章向大家介绍MyBatis 的 `<if test="">` 语句里面使用反单引号的问题,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

如下是 MyBatis 的映射文件。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.renda.dao.CourseMapper">

    <!--
        多条件课程列表查询
    -->
    <select id="findCourseByCondition" parameterType="courseVo" resultType="course">
        select * from course
        <where>
            <if test="courseName != null and courseName != ''">
                and course_name like concat('%', #{courseName}, '%')
            </if>
            <if test="`status` != null and `status` != ''">
                and `status` = #{status}
            </if>
            <if test="true">
                and is_del != 1
            </if>
        </where>
    </select>

</mapper>

启动了 Tomcat 服务器,使用 Postman 进行测试,使用了 log4j 输出 MyBatis 相关的 log。

当 status 为 1 时,无论有没有为 status 加反单引号,输出结果都是正确的:

::, DEBUG SpringManagedTransaction: - JDBC Connection [com.mysql.jdbc.JDBC4Connection@fd1a13d] will not be managed by Spring
::, DEBUG findCourseByCondition: - ==>  Preparing: select * from course WHERE course_name like concat('%', ?, '%') and `status` = ? and is_del !=  
::, DEBUG findCourseByCondition: - ==> Parameters: Vue.js 3.0 核心源码解析(String), (Integer)
::, DEBUG findCourseByCondition: - <==      Total: 

当 status 为 0 时,如果 <if test> 的 status 没有加反单引号,即便里面的 status 加了反单引号,输出结果是错误的:

<if test="status != null and status != ''">
    and `status` = #{status}
</if>
::, DEBUG SpringManagedTransaction: - JDBC Connection [com.mysql.jdbc.JDBC4Connection@d4a78] will not be managed by Spring
::, DEBUG findCourseByCondition: - ==>  Preparing: select * from course WHERE course_name like concat('%', ?, '%') and is_del !=  
::, DEBUG findCourseByCondition: - ==> Parameters: Vue.js 3.0 核心源码解析(String)
::, DEBUG findCourseByCondition: - <==      Total: 

可以看到这时候的 <if test> 执行并没有通过,导致少追加了 status 的判断。

只有在 <if test> 的 status 加上反单引号,执行结果才是正确的:

<if test="`status` != null and `status` != ''">
    and `status` = #{status}
</if>
::, DEBUG SpringManagedTransaction: - JDBC Connection [com.mysql.jdbc.JDBC4Connection@af06d] will not be managed by Spring
::, DEBUG findCourseByCondition: - ==>  Preparing: select * from course WHERE course_name like concat('%', ?, '%') and `status` = ? and is_del !=  
::, DEBUG findCourseByCondition: - ==> Parameters: Vue.js 3.0 核心源码解析(String), (Integer)
::, DEBUG findCourseByCondition: - <==      Total: 

整数类型的 isFree 也会出现这个问题,加上反单引号:

<if test="`isFree` != null and `isFree` != ''">
    is_free = #{isFree},
</if>

由此可以推测出:整数类型转字符串类型后,0 代表空字符串的意思,加上反单引号可以把整数类型的 0 直接转为 字符 0

同样道理,status 是整数类型,当它为 0 时,进行字符串转型会把它转为 null;加上反单引号就不会出错了。

但是加上反单引号却有另外一个问题,就是当 status 为 Integer 类型时, status 可以为 null,这时候使用反单引号进行整数类型转字符串类型会把 null 本身转为字符串 "null",从而导致判断出错。

所以,当 status 为 Integer 且可能为 null 时,最好是用以下方式解决:

<if test="status != null and status != '' or status == 0">
    and `status` = #{status}
</if>