• 笔记:MyBatis 动态SQL


    有时候,静态的SQL语句并不能满足应用程序的需求。我们可以根据一些条件,来动态地构建SQL语句。例如,在Web应用程序中,有可能有一些搜索界面,需要输入一个或多个选项,然后根据这些已选择的条件去执行检索操作。在实现这种类型的搜索功能,我们可能需要根据这些条件来构建动态的SQL语句。如果用户提供了任何输入条件,我们需要将那个条件 添加到SQL语句的WHERE子句中。

    MyBatis通过使用<if>,<choose>,<where>,<foreach>,<trim>元素提供了对构造动态SQL语句的高级别支持。

    1. if 语句

      <if>元素被用来有条件地嵌入SQL片段,如果测试条件被赋值为true,则相应地SQL片段将会被添加到SQL语句中。

      假定我们有一个课程搜索界面,设置了 讲师(Tutor)下拉列表框,课程名称(CourseName)文本输入框,开始时间(StartDate)输入框,结束时间(EndDate)输入框,作为搜索条件。假定课讲师下拉列表是必须选的,其他的都是可选的。

      当用户点击 搜索按钮时,我们需要显示符合以下条件的成列表:

    •   特定讲师的课程
    •   课程名包含输入的课程名称关键字的课程;如果课程名称输入为空,则取所有课程
    •   在开始时间和结束时间段内的课程

    我们可以对应的映射语句,如下所示:

    <resultMap type="Course" id="CourseResult">

        <id column="course_id" property="courseId" />

        <result column="name" property="name" />

        <result column="description" property="description" />

        <result column="start_date" property="startDate" />

        <result column="end_date" property="endDate" />

    </resultMap>

    <!-- 查询输入参数定义为 hashmap 类型 -->

    <select id="searchCourses" parameterType="hashmap" resultMap="CourseResult">

            SELECT * FROM COURSES

                    WHERE TUTOR_ID= #{tutorId}

            <if test="courseName != null">

            AND NAME LIKE #{courseName}

            </if>

            <if test="startDate != null">

            AND START_DATE >= #{startDate}

            </if>

            <if test="endDate != null">

            AND END_DATE <= #{endDate}

            </if>

    </select>

    Java代码如下:

        public interface CourseMapper

        {

         List<Course> searchCourses(Map<String, Object> map);

        }

        public void searchCourses()

        {

         Map<String, Object> map = new HashMap<String, Object>();

         map.put("tutorId", 1);

         map.put("courseName", "%java%");

         map.put("startDate", new Date());

         CourseMapper mapper = sqlSession.getMapper(CourseMapper.class);

         List<Course> courses = mapper.searchCourses(map);

         for (Course course : courses)

         {

    System.out.println(course);

         }

        }

    1. choose,when 和otherwise 条件

      有时候,查询功能是以查询类别为基础的。首先,用户需要选择是否希望通过选择讲师,课程名称,开始时间,或结束时间作为查询条件类别来进行查询,然后根据选择的查询类别,输入相应的参数。在这样的情景中,我们需要只使用其中一种查询类别。

      MyBatis 提供了<choose>元素支持此类型的SQL预处理。

      现在让我们书写一个适用此情景的SQL映射语句。如果没有选择查询类别,则查询开始时间在今天之后的课程,代码如下:

      <select id="searchCourses" parameterType="hashmap" resultMap="CourseResult">

              SELECT * FROM COURSES

              <choose>

                      <when test="searchBy == 'Tutor'">

                              WHERE TUTOR_ID= #{tutorId}

                      </when>

                      <when test="searchBy == 'CourseName'">

                              WHERE name like #{courseName}

                      </when>

                      <otherwise>

                              WHERE TUTOR start_date >= now()

                      </otherwise>

              </choose>

      </select>

      MyBatis计算<choose>测试条件的值,且使用第一个值为TRUE的子句。如果没有条件为true,则使用<otherwise>内的子句。

    2. where 条件

      有时候,所有的查询条件(criteria)应该是可选的。在需要使用至少一种查询条件的情况下,我们应该使用WHERE子句。并且, 如果有多个条件,我们需要在条件中添加AND或OR。MyBatis提供了<where>元素支持这种类型的动态SQL语句。

      在我们查询课程界面,我们假设所有的查询条件是可选的。进而,当需要提供一个或多个查询条件时,应该改使用WHERE子句。

      <select id="searchCourses" parameterType="hashmap" resultMap="CourseResult">

              SELECT * FROM COURSES

              <where>

                      <if test=" tutorId != null ">

                              TUTOR_ID= #{tutorId}

                      </if>

                      <if test="courseName != null">

                              AND name like #{courseName}

                      </if>

                      <if test="startDate != null">

                              AND start_date >= #{startDate}

                      </if>

                      <if test="endDate != null">

                              AND end_date <= #{endDate}

                      </if>

              </where>

      </select>

      <where>元素只有在其内部标签有返回内容时才会在动态语句上插入WHERE条件语句。并且,如果WHERE子句以AND或者OR打头,则打头的AND或OR将会被移除。如果tutor_id参数值为null,并且courseName参数值不为null,则<where>标签会将AND name like#{courseName} 中的AND移除掉,生成的SQL WHERE子句为:where name like#{courseName}。

    3. trim条件

      <trim>元素和<where>元素类似,但是<trim>提供了在添加前缀/后缀 或者移除前缀/后缀方面提供更大的灵活性

      <select id="searchCourses" parameterType="hashmap" resultMap="CourseResult">

      SELECT * FROM COURSES

      <trim prefix="WHERE" prefixOverrides="AND | OR">

      <if test=" tutorId != null ">

      TUTOR_ID= #{tutorId}

      </if>

      <if test="courseName != null">

      AND name like #{courseName}

      </if>

      </trim>

      </select>

      这里如果任意一个<if>条件为true,<trim>元素会插入WHERE,并且移除紧跟WHERE后面的AND或OR

    4. foreach循环

      另外一个强大的动态SQL语句构造标签即是<foreach>。它可以迭代遍历一个数组或者列表,构造AND/OR条件或一个IN子句。

      假设我们想找到tutor_id为1,3,6的讲师所教授的课程,我们可以传递一个tutor_id组成的列表给映射语句,然后通过<foreach>遍历此列表构造动态SQL。

      注意:如果参数类型为 List 则其 <foreach…/> collection 设置为 list,如果为 map 则设置为集合的 key 名称。

      <select id="searchCoursesByTutors" parameterType="map" resultMap="CourseResult">

      SELECT * FROM COURSES

      <if test="tutorIds != null">

      <where>

      <foreach item="tutorId" collection="tutorIds">

      OR tutor_id=#{tutorId}

      </foreach>

      </where>

      </if>

      </select>

         

      Java代码:

      public interface CourseMapper

      {

              List<Course> searchCoursesByTutors(Map<String, Object> map);

      }

      public void searchCoursesByTutors()

      {

              Map<String, Object> map = new HashMap<String, Object>();

              List<Integer> tutorIds = new ArrayList<Integer>();

              tutorIds.add(1);

              tutorIds.add(3);

              tutorIds.add(6);

              map.put("tutorIds", tutorIds);

              CourseMapper mapper =

                      sqlSession.getMapper(CourseMapper.class);

              List<Course> courses = mapper.searchCoursesByTutors(map);

              for (Course course : courses)

              {

                      System.out.println(course);

              }

      }

      现在让我们来看一下怎样使用<foreach>生成 IN子句:

      <select id="searchCoursesByTutors" parameterType="map" resultMap="CourseResult">

              SELECT * FROM COURSES

              <if test="tutorIds != null">

                      <where>

      tutor_id IN

                              <foreach item="tutorId" collection="tutorIds"  open="(" separator="," close=")">

       #{tutorId}

                              </foreach>

                      </where>

              </if>

      </select>

    5. set条件

      <set>元素和<where>元素类似,如果其内部条件判断有任何内容返回时,他会插入SET SQL片段。

      <update id="updateStudent" parameterType="Student">

              update students

              <set>

              <if test="name != null">name=#{name},</if>

              <if test="email != null">email=#{email},</if>

              <if test="phone != null">phone=#{phone},</if>

              </set>

              where stud_id=#{id}

      </update>

      这里,如果<if>条件返回了任何文本内容,<set>将会插入set关键字和其文本内容,并且会剔除将末尾的 ","。

      在上述的例子中,如果 phone!=null,<set>将会让会移除 phone=#{phone}后的逗号",",生成 set phone=#{phone} 。

         

  • 相关阅读:
    【miscellaneous】海康威视监控摄像头实现web端无插件监控实拍效果
    【miscellaneous】海康威视监控摄像头实现web端无插件监控实拍效果
    【miscellaneous】单播、广播和多播IP地址
    【miscellaneous】单播、广播和多播IP地址
    【miscellaneous】IP多播技术及其编程
    【miscellaneous】IP多播技术及其编程
    【miscellaneous】多播的实现和需要注意的问题
    【miscellaneous】多播的实现和需要注意的问题
    【VS开发】组播(多播)的C程序实战
    【VS开发】组播(多播)的C程序实战
  • 原文地址:https://www.cnblogs.com/li3807/p/7061891.html
Copyright © 2020-2023  润新知