mybatis中的動態SQL語句


有時候,靜態的SQL語句並不能滿足應用程序的需求。我們可以根據一些條件,來動態地構建 SQL語句。

例如,在Web應用程序中,有可能有一些搜索界面,需要輸入一個或多個選項,然后根據這些已選擇的條件去執行檢索操作。我們可能需要根據用戶選擇的條件來構建動態的SQL語句。如果用戶提供了任何一個條件,我們需要將那個條件添加到SQL語句的WHERE子句中。

!以下內容基於自己建的表和類!

1.<if>標簽被用來通過條件嵌入SQL片段,如果條件為true,則相應地SQL片段將會被添加到SQL語句中。
例如:
假定有一個課程搜索界面,設置了講師(Tutor)下拉列表框,課程名稱(CourseName)文本輸入框,開始時間(StartDate)輸入框,結束時間(EndDate)輸入框,作為搜索條件。假定課講師下拉列表是必須選的,其他的都是可選的。當用戶點擊搜索按鈕時,需要顯示符合條件的列表數據。

對應的sql映射文件,如下所示:

<!-- 獨立的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> 

映射接口:

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

測試方法:

@Test
public void test_searchCourses1(){

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", "%Java%"); 

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 和 otherwise 條件
有時候,查詢功能是以查詢類別為基礎的。首先,用戶需要先選擇是通過講師查詢,還是課程名稱查詢,還是開始時間查詢。然后根據選擇的查詢類別,輸入相應的參數,再進行查詢。

例如,頁面中有一個下拉列表,可以選擇查詢的類別,可以選擇根據講師查詢、根據課程名查詢、根據時間查詢等等,選擇了列表之后,再輸入關鍵字進行查詢。

MyBatis提供了<choose>標簽可以支持此類型的查詢處理。 假設如果用戶都沒有選擇,那么默認可以根據當前時間進行查詢。

注意:mysql中now()表示當前時間 oracle需要使用sysdate

對應的sql映射文件,如下所示:

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

測試方法:

@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計算<choose>中條件的值,並使用第一個值為TRUE的子句。如果沒有條件為 true,則使用<otherwise>內的子句。

 

3.Where 條件
有時候,所有的查詢條件應該是可選的。在需要使用至少一種查詢條件的情況下,可以直接使用WHERE子句。
如果有多個條件,我們需要在條件中添加AND或OR。MyBatis提供了<where>元素支持這種類型的動態SQL語句。

例如,在查詢課程界面,假設所有的查詢條件是可選的。

注意,<where>元素只有在其內部標簽有返回內容時才會在動態語句上插入WHERE條件語句。
並且,如果WHERE子句以AND或者OR打頭,則打頭的AND或OR將會被移除。

映射文件:

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

測試方法:

@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>條件
<trim>元素和<where>元素類似,但是<trim>提供了添加 前綴/后綴 或者 移除 前綴/后綴 的功能。

映射文件:

<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表示有一個if成立則插入where語句,沒有if成立,就會去掉where直接查詢
suffix表示后綴,和prefix相反

suffixOverrides="and"表示如果最后生成的sql語句多一個and,則自動去掉.
prefixOverrides的意思是處理前綴,和suffixOverrides相反

測試方法:

@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 循環
另外一個強大的動態SQL語句構造標簽是<foreach>。它可以迭代遍歷一個數組或者列表,構造AND/OR條件或一個IN子句。

假設查詢tutor_id為 1,3,6的講師所教授的課程,我們可以傳遞一個tutor_id組成的列表給映射語句,然后通過<foreach>遍歷此列表構造動態SQL。

映射文件:

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

映射接口:

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

測試方法:

@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();
}
}

和上面同樣的功能,使用<foreach>生成IN子句:

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

測試方法保持不變。

 

6.set 條件,專用於UPDATE更新操作

<set>元素和<where>元素類似,但是set元素只是針對update更新語句使用的。

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

這里,如果<if>條件返回了任何文本內容,<set>將會插入set關鍵字和其文本內容,並且會剔除將末尾的逗號","。

測試方法:

@Test
public void test_updateStudent(){

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

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

Student student = new Student();
student.setStudId(45);
student.setEmail("xx@briup.com");

mapper.updateStudent(student);

sqlSession.commit();

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM