java动态拼接select sql jpa动态拼接sql_List


三、动态SQL

经常遇到很多按照很多查询条件进行查询的情况,比如智联招聘的职位搜索,比如OA系统中的支出查询等。其中经常出现很多条件不取值的情况,在后台应该如何完成最终的SQL语句呢?


java动态拼接select sql jpa动态拼接sql_数组_02


java动态拼接select sql jpa动态拼接sql_数组_03


如果采用JDBC进行处理,需要根据条件是否取值进行SQL语句的拼接,一般情况下是使用StringBuilder类及其append方法实现,还是有些繁琐的。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。

MyBatis在简化操作方法提出了动态SQL功能,将使用Java代码拼接SQL语句,改变为在XML映射文件中截止标签拼接SQL语句。相比而言,大大减少了代码量,更灵活、高度可配置、利于后期维护。

MyBatis中动态SQL是编写在mapper.xml中的,其语法和JSTL类似,但是却是基于强大的OGNL表达式实现的。

MyBatis也可以在注解中配置SQL,但是由于注解功能受限,尤其是对于复杂的SQL语句,可读性很差,所以较少使用。

定义如下接口及其功能来练习动态SQL语句。


public interface EmployeeMapper {
 public List<Employee> findEmp(@Param("job") String job,
 @Param("deptno") int deptno,
 @Param("sal") double sal);
 public List<Employee> findEmp2(@Param("job") String job,
 @Param("deptno") int deptno,
 @Param("sal") double sal);
 public List<Employee> findEmp3(@Param("ename") String ename,
 @Param("job") String job);
 public List<Employee> findEmp4(@Param("ename") String ename,
 @Param("job") String job);
 public int updateEmp(String job,double sal,int empno);
 public List<Employee> findEmp5(List<Integer> deptNoList);
 public List<Employee>
 findEmp6(@Param("deptnoList") List<Integer> deptNoList);
 public List<Employee> findEmp7(int [] arr);
}


3.1 if

每一个if相当于一个if单分支语句。一般添加一个where 1=1 的查询所有数据的条件,作为第一个条件。这样可以让后面每个if语句的SQL语句都以and开始。


<mapper namespace="com.bjsxt.mapper.EmployeeMapper">
    <select id="findEmp" resultType="employee">
        select * from emp where 1=1
        <if test="job!=null and job !='' ">
            and job =#{job}
        </if>
        <if test="deptno !=0 ">
            and deptno = #{deptno}
        </if>
        <if test="sal>0">
            and sal > #{sal}
        </if>
    </select>
</mapper>


3.2 where

使用where元素,就不需要提供where 1=1 这样的条件了。如果标签内容不为空字符串则自动添加where关键字,并且会自动去掉第一个条件前面的and或or。


<mapper namespace="com.bjsxt.mapper.EmployeeMapper">
    <select id="findEmp2" resultType="employee">
        select * from emp
        <where>
            <if test="job!=null and job !='' ">
                and job =#{job}
            </if>
            <if test="deptno >0 ">
                and deptno = #{deptno}
            </if>
            <if test="sal>0">
                and sal > #{sal}
            </if>
        </where>
    </select>   
</mapper>


3.3 bind

bind主要的一个重要场合是模糊查询,通过bind通配符和查询值,可以避免使用数据库的具体语法来进行拼接。比如MySQL中通过concat来进行拼接,而Oracle中使用||来进行拼接。


<mapper namespace="com.bjsxt.mapper.EmployeeMapper">
   <select id="findEmp3" resultType="employee">
        select * from emp where ename like concat("%",#{ename},"%" ) 
and job  like concat("%",#{job},"%" )
    </select>
    <select id="findEmp4" resultType="employee">
        <bind name="cename" value="'%'+ename+'%'"></bind>
        <bind name="cjob" value="'%'+job+'%'"></bind>
        select * from emp where ename like #{cename} and job  like #{cjob}
    </select>
</mapper>


3.4 set

set元素用在update语句中给字段赋值。借助if的配置,可以只对有具体值的字段进行更新。set元素会自动帮助添加set关键字,自动去掉最后一个if语句的多余的逗号。


<mapper namespace="com.bjsxt.mapper.EmployeeMapper">
    <update id="updateEmp">
        update emp
        <set>
            <if test="param1!=null and param1 != ''">
                job = #{param1},
            </if>
            <if test="param2>0">
                sal = #{param2}
            </if>
        </set>
        where empno = #{param3}
    </update>
</mapper>


3.5 foreach

foreach 元素是非常强大的,它允许你指定一个集合或者数组,声明集合项和索引变量,它们可以用在元素体内。它也允许你指定开放和关闭的字符串,在迭代之间放置分隔符。这个元素是很智能的,它不会偶然地附加多余的分隔符。

注意 你可以传递一个 List 实例或者数组作为参数对象传给 MyBatis。当你这么做的时候,MyBatis 会自动将它包装在一个 Map 中,用名称在作为键。List 实例将会以“list” 作为键,而数组实例将会以“array”作为键。


<mapper namespace="com.bjsxt.mapper.EmployeeMapper">
    <select id="findEmp5" resultType="employee">
        select * from emp where deptno in
        <foreach collection="collection" item="deptno" 
open="(" separator="," close=")">
            #{deptno}
        </foreach>
    </select>

    <select id="findEmp6" resultType="employee">
        select * from emp where deptno in
        <foreach collection="deptnoList" item="deptno" 
open="(" separator="," close=")">
            #{deptno}
        </foreach>
    </select>

    <select id="findEmp7" resultType="employee">
        select * from emp where deptno in
        <foreach collection="array" item="deptno"
 open="(" separator="," close=")">
            #{deptno}
        </foreach>
    </select>
</mapper>


在进行SQL优化是有一点就是建议少使用in语句,因为对性能有影响。如果in中元素很多的话,会对性能有较大影响,此时就不建议使用foreach语句了。

作业

1. 动态SQL的优势

2. 练习动态SQL语句