MyBatis in-depth understanding of dynamic SQL statements

Sometimes, static SQL statement and can not meet the needs of the application. We can based on some conditions, dynamically constructed SQL statements.

For example, in a Web application, there may be some search interface, you need to enter one or more options, and then to perform the retrieval operation under these conditions you have selected. We may need depending on the conditions selected by the user to build dynamic SQL statements. If the user provides any of these conditions, we need to add the condition to the WHERE clause of a SQL statement.

! Based on the following table and build their own class!

1. <if> tag is used by the embedded SQL fragments conditions, if the condition is true, the corresponding SQL fragments will be added to the SQL statement.
 For example:
 suppose you have a course search interface, set Lecturer (Tutor) drop-down list box, course name (CourseName) text input box, start time (StartDate) input box, input box end time (EndDate), as the search condition. Course instructor is assumed to be selected in the drop-down list, the others are optional. When the user clicks the Search button, you need to display a list of qualified data.

Sql corresponding mapping file, as follows:

<!-- 独立的Course封装映射 -->
<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>

 

<!-- 查询Course的select语句,里面加入了if条件判断 -->
<select id="searchCourses" parameterType="map" 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 <![CDATA[ <= ]]> #{endDate}
</if>
</select>

Mapping interface:

public interface DynamicSqlMapper{
List<Course> searchCourses(Map<String, Object> map);
}

testing method:

@Test
public void test_searchCourses1(){

SqlSession sqlSession = null;
try {
sqlSession = MyBatisSqlSessionFactory.openSession();

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

LocalDate date = LocalDate.of(2019, 1, 10);
map.put("startDate", date);

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

courses.forEach(System.out::println);

} catch (Exception e) {
e.printStackTrace();
}
}

2.choose, when conditions and otherwise
 Sometimes, the query is a query function-based categories. First, the user need to select a query by a lecturer or course name query, or query start time. The query then select category enter parameters, then the query.

For example, the page has a drop-down list, select a category query, the query can be selected according to the lecturer, course name based on the query, according to the time after the inquiry and so on, select a list, then enter a keyword to search.

MyBatis provides <choose> tag can support this type of query processing. Assume that if users do not choose, the default can be queried according to the current time.

Sql corresponding mapping file, as follows:

<select id="searchCourses" parameterType="map" 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 start_date >= sysdate
</otherwise>
</choose>
</select>

testing method:

@Test
public void test_searchCourses2(){

SqlSession sqlSession = null;
try {
sqlSession = MyBatisSqlSessionFactory.openSession();

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

Map<String,Object> map = new HashMap<String,Object>();
//    map.put("searchBy", "Tutor");
//    map.put("tutorId", 1);
map.put("searchBy", "CourseName");
map.put("courseName", "%MyBatis%");

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

courses.forEach(System.out::println);

} catch (Exception e) {
e.printStackTrace();
}
}

MyBatis calculated <choose> value condition, and uses the first clause is TRUE. If no condition is true, the clause in the <otherwise>.

3.Where conditions
 Sometimes, all of the query should be optional. In case of need to use at least one query, you can directly use the WHERE clause.
If there are multiple conditions, we need to add an AND or OR in the criteria. MyBatis provides a <where> element to support this type of dynamic SQL statements.

For example, the query interface course, assuming that all of the query is optional.

Note, <where> element only if a conditional statement inserted in the dynamic WHERE statements return the contents inside label.
 And, if the WHERE clause starts to AND and OR, AND or OR of the beginning will be removed.

Mapping file:

<select id="searchCourses" parameterType="map" 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>
</where>
</select>

testing method:

@Test
public void test_searchCourses3(){

SqlSession sqlSession = null;
try {
sqlSession = MyBatisSqlSessionFactory.openSession();

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

Map<String,Object> map = new HashMap<String,Object>();
//map.put("tutorId", 1);
//map.put("courseName", "JavaSE");
//map.put("startDate", LocalDate.of(2019, 1, 10));

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

courses.forEach(System.out::println);

} catch (Exception e) {
e.printStackTrace();
}
}

4. <trim> conditions
<trim> element and the like <where> element, the <trim> Providing adding a prefix / suffix removal or prefix / suffix function.

Mapping file:

<select id="searchCourses" parameterType="map" resultMap="CourseResult">
SELECT * FROM COURSES
<trim prefix="WHERE" suffixOverrides="and">
<if test=" tutorId != null ">
TUTOR_ID = #{tutorId} and
</if>
<if test="courseName != null">
name like #{courseName} and
</if>
</trim>
</select>

prefix indicate if there is a set up where you insert statements, if not established, it will be removed where a direct query
suffix expresses a contrary suffix and prefix

suffixOverrides = "and" indicates that if the last generated sql statement and a plurality, is automatically removed.
prefixOverrides prefix processing means, and the opposite suffixOverrides

testing method:

@Test
public void test_searchCourses4(){

SqlSession sqlSession = null;
try {
sqlSession = MyBatisSqlSessionFactory.openSession();

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

Map<String,Object> map = new HashMap<String,Object>();
//    map.put("tutorId", 1);
//    map.put("courseName", "JavaSE");

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

courses.forEach(System.out::println);

} catch (Exception e) {
e.printStackTrace();
}
}

5.foreach cycle
 Another powerful dynamic SQL statement structure tag is <foreach>. It can iterate through a list or array, configured AND / OR IN clause or condition.

Suppose the query tutor_id as 1,3,6 instructors taught the course, we can pass a tutor_id of a list of statements to the map, and then the list is traversed construct dynamic SQL by <foreach>.

Mapping file:

<select id="searchCoursesByTutors" parameterType="map" resultMap="CourseResult">
SELECT * FROM COURSES
<if test="tutorIds != null">
<where>
<!-- 在这里的 tutorId指的是集合中存入准备查询的tutor_id-->
<foreach item="tutorId" collection="tutorIds">
OR tutor_id = #{tutorId}
</foreach>
</where>
</if>
</select>

Mapping interface:

public interface DynamicSqlMapper{
List<Course> searchCoursesByTutors(Map<String,Object> map);
}

testing method:

@Test
public void test_searchCoursesByTutors(){

SqlSession sqlSession = null;
try {
sqlSession = MyBatisSqlSessionFactory.openSession();

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

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);

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

courses.forEach(System.out::println);

} catch (Exception e) {
e.printStackTrace();
}
}

And the same function as above, using <foreach> IN generated clause:

<select id="searchCoursesByTutors" parameterType="map" resultMap="CourseResult">
SELECT * FROM COURSES
<if test="tutorIds != null">
<where>
tutor_id IN
<foreach item="tempValue" collection="tutorIds" open="(" separator="," close=")">
#{tempValue}
</foreach>
</where>
</if>
</select>

Test methods remain unchanged.

6.set conditions specific to UPDATE update

<Set> similar elements and <where> element, but the set of elements used for the update just update statement.

<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=#{studId}
</update>

Here, if the <if> condition returns any text, <set> will insert keywords and set its text content and will be removed at the end of a comma "."

testing method:

@Test
public void test_updateStudent(){

SqlSession sqlSession = null;
try {
sqlSession = MyBatisSqlSessionFactory.openSession();

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

mapper.updateStudent(student);

sqlSession.commit();

} catch (Exception e) {
e.printStackTrace();
}
}

Guess you like

Origin www.linuxidc.com/Linux/2019-11/161478.htm