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;

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM