MyBatis(五)动态SQL 之 if 与 where 标签

一、SQL 多条件来查询

  1、在 EmployeeMapper 接口中声明方法

//根据id, lastNname, age, sex多条件查询员工信息
public List<Emp> getEmpListByMoreCondition(Emp  emp);

  2、在 EmployeeMapper.xml 中配置 SQL 语句

     <!--
         public List<Emp> getEmpListByMoreCondition(Emp  emp);
         多条件查询:若页面中没有设置此条件,SQL语句中一定不能有该条件
      -->
     <select id="getEmpListByMoreCondition1"  resultType="Emp">
         select eid,ename,age,sex,did from emp
         where
              id = #{id}
              and last_name = #{lastName}
              and age = #{age}
              and sex = #{sex}
     </select>

    在这里可以看到,使用的是 SQL 拼接的方式,来进行多条件查询的。

二、使用 if 标签实现多条件查询

  1、在 EmployeeMapperDynamicSQL 接口中声明方法

public List<Employee> getEmpsByConditionIf(Employee employee);

  2、在 EmployeeMapperDynamicSQL.xml 中进行配置

    <!--
        1、查询员工:要求携带了哪个字段查询条件就带上这个字段的值
        public List<Employee> getEmpsByConditionIf(Employee employee);
    -->
    <!--
        test:判断表达式(OGNL)表达式
            OGNL 表达式参照官方文档或PPT
        c:if test
        从参数中取值进行判断
        遇见特殊符号应该去写转义字符:
        " : &quot;
        & : &amp;

        OGNL 会进行字符串和与数字的转换判断
    -->
    <select id="getEmpsByConditionIf" resultType="Employee">
        select * from tbl_employee
        where
            <if test="id!=null">
                id=#{id}
            </if>
            <if test="lastName!=null and lastName!=''">
                and last_name like #{lastName}
            </if>
            <if test="email!=null and email.trim()!=&quot;&quot;">
                and email = #{email}
            </if>
            <if test="gender==0 or gender==1">
                and gender = #{gender}
            </if>
    </select>

    <if> 标签的作用:通过 test 表达式,用于拼接 SQL,如果 test 为 true,将其中的 SQL 进行拼接,否则不进行拼接。

    

  3、细节问题1

    当我们把 gender 字段改为"男、女"的字符格式时,然后重新修改 xml 中的配置:

  <select id="getEmpsByConditionIf" resultType="Employee">
        select * from tbl_employee
        <where>
            <if test="id!=null">
                id=#{id}
            </if>
            <if test="lastName!=null and lastName!=''">
                and last_name like #{lastName}
            </if>
            <if test="email!=null and email.trim()!=&quot;&quot;">
                and email = #{email}
            </if>
            <if test="gender == '男' or gender == '女'">
                and gender = #{gender}
            </if>
        </where>
    </select>

    测试信息:

     @Test
     public void testIf() throws IOException {
          //1、获取 sqlSessionFactory
          SqlSessionFactory sqlSessionFactory = getsqlSessionFactory();

          //2、获取 sqlSession 实例,能直接执行已经映射的 SQL 语句
          SqlSession sqlSession = sqlSessionFactory.openSession();

          try {
               EmployeeMapperDynamicSQL mapper = sqlSession.getMapper(EmployeeMapperDynamicSQL.class);
               //select * from tbl_employee where id=? and last_name like ? and email = ?
               Employee employee = new Employee(null, "%o%", "男","tom@126.com");
               List<Employee> emps = mapper.getEmpsByConditionIf(employee);
               emps.forEach(System.out::println);
          } finally {
               sqlSession.close();
          }

    运行结果:

   我们发现,这时并不能正常执行。

  重新修改配置文件:

  <select id="getEmpsByConditionIf" resultType="Employee">
        select * from tbl_employee
        <where>
            <if test="id!=null">
                id=#{id}
            </if>
            <if test="lastName!=null and lastName!=''">
                and last_name like #{lastName}
            </if>
            <if test="email!=null and email.trim()!=&quot;&quot;">
                and email = #{email}
            </if>
            <if test='gender == "男" or gender == "女"'>
                and gender = #{gender}
            </if>
        </where>
    </select>

     修改了映射文件,重新运行。

     运行成功。

    小结

    (1)if 标签中判断字符串变量是否是字符串的时候,发现并不管用;

    (2)如果把变量的值用双引号引起来,外面使用 单引号,这时就成功了;

    (3)只能解释为 MyBatis 会把 '男' 解析为字符,而需要的是字符串,java 是强类型语言,字符串和字符不能直接比较,所以需要使用双引号。

  4、细节问题2

    对于上面的拼接条件,如果使用了多条件拼接查询,当有多个匹配条件时,可以使用 and 来连接。

    但是如果第一个条件如果不进行拼接,就会出现 where 后面多出一个 and 的情况。

    例如上面的情况,如果 id 为 null,就不会进行拼接该 SQL 片段,而是直接拼接第二个条件,这时就会出现一个 and 字段

select * from tbl_employee where and last_name = ? and email = ? and gender = ?

      这时 SQL 的执行就会出现问题。

  5、解决方案一

    在 where 后面添加一个恒成立的情况,如果第一个条件不匹配,也不会不执行。

    <select id="getEmpsByConditionIf" resultType="Employee">
        select * from tbl_employee
        where 1=1
            <if test="id!=null">
                and id=#{id}
            </if>
            <if test="lastName!=null and lastName!=''">
                and last_name like #{lastName}
            </if>
            <if test="email!=null and email.trim()!=&quot;&quot;">
                and email = #{email}
            </if>
            <if test="gender==0 or gender==1">
                and gender = #{gender}
            </if>
    </select>

    执行的 SQL 语句:

select * from tbl_employee where 1=1 and last_name = ? and email = ? and gender = ?

     常用的恒等式有:

2>1
1=1
true

  

  6、解决方案二

    使用下面的 where 标签

三、使用 where 条件

  使用 where 标签优化多查询查询(方案二)
  <where> 标签的作用:添加where关键字,同时去掉多余的and
  修改上面 xml 中的配置
    <select id="getEmpsByConditionIf" resultType="Employee">
        select * from tbl_employee
        <where>
            <if test="id!=null">
                id=#{id}
            </if>
            <if test="lastName!=null and lastName!=''">
                and last_name like #{lastName}
            </if>
            <if test="email!=null and email.trim()!=&quot;&quot;">
                and email = #{email}
            </if>
            <if test="gender==0 or gender==1">
                and gender = #{gender}
            </if>
        </where>
    </select>
  这时如果 id 还是 null,而不用再在 where 后面加恒等式,也可以执行成功。where 标签会把多余的 and 去掉。
  执行的 SQL 语句:
select * from tbl_employee WHERE last_name like ? and email = ?

  

  注意

  (1)if 标签和 where 标签不一定必须同时使用,按实际需要进行使用;

  (2)if 标签用于完成简单的判断;

  (3)where 用于解决 SQL 语句中 where 关键字以及条件中第一个 and 或者 or 的问题;

  (4)mybatis就会将where标签中拼装的sql,多出来的and或者or去掉,where只会去掉第一个多出来的and或者or。

四、总结

  查询的时候如果某些字段没带可能 SQL 拼装会有问题。

  (1)给 where 后面加上1=1,以后的条件都是 and xxx;

  (2)mybatis 使用where标签来将所有的查询条件包括在内,mybatis 就会将where标签中拼装的SQL,多出来的and或者or去掉;

  (3)where 只会去掉第一个多出来的and或者or;

原文地址:https://www.cnblogs.com/niujifei/p/15239258.html