手機版
你好,游客 登錄 注冊
背景:
閱讀新聞

深入理解MyBatis中的動態SQL語句

[日期:2019-11-21] 來源:Linux社區  作者:Magic-Li [字體: ]

有時候,靜態的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("[email protected]");

mapper.updateStudent(student);

sqlSession.commit();

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

Linux公社的RSS地址http://www.okbuvi.live/rssFeed.aspx

本文永久更新鏈接地址http://www.okbuvi.live/Linux/2019-11/161478.htm

linux
相關資訊       動態SQL  MyBatis動態SQL 
本文評論   查看全部評論 (0)
表情: 表情 姓名: 字數

       

評論聲明
  • 尊重網上道德,遵守中華人民共和國的各項有關法律法規
  • 承擔一切因您的行為而直接或間接導致的民事或刑事法律責任
  • 本站管理人員有權保留或刪除其管轄留言中的任意內容
  • 本站有權在網站內轉載或引用您的評論
  • 參與本評論即表明您已經閱讀并接受上述條款
海口彩票论坛