演示預設學習使用者scott,預設密碼是tiger
1.動態SQL
-
【官方宣告】
動態 SQL 是 MyBatis 的強大特性之一。如果你使用過 JDBC 或其它類似的框架,你應該能理解根據不同條件拼接 SQL 語句有多痛苦,例如拼接時要確保不能忘記新增必要的空格,還要注意去掉列表最後一個列名的逗號。利用動態 SQL,可以徹底擺脫這種痛苦。
使用動態 SQL 並非一件易事,但藉助可用於任何 SQL 對映語句中的強大的動態 SQL 語言,MyBatis 顯著地提升了這一特性的易用性。
如果你之前用過 JSTL 或任何基於類 XML 語言的文字處理器,你對動態 SQL 元素可能會感覺似曾相識。在 MyBatis 之前的版本中,需要花時間瞭解大量的元素。藉助功能強大的基於 OGNL 的表示式,MyBatis 3 替換了之前的大部分元素,大大精簡了元素種類,現在要學習的元素種類比原來的一半還要少。
1.1 IF關鍵字
1.1.1 動態SQL測試
-
dao層 介面 => 【BlogsMapper】
import java.util.List; import java.util.Map; public interface BlogsMapper { // 建立【插入測試資料】的方法 int addBlog(Blogs blog); // 建立【實現動態SQL查詢】的方法 List<Blogs> getBlogsByDynamicSQL(Map<String,String> map); }
-
XML對映檔案 => 【BlogsMapper.xml】
<select id="getBlogsByDynamicSQL"> <!-- 注意: where 1 = 1 儘量不使用 --> select * from test.blog where 1 = 1 <!-- <if>標籤: 當向資料庫傳送的請求中,【title】欄位不為空時,則新增【title】欄位的查詢過濾條件 --> <if test="title != null"> and title = #{title} </if> <!-- <if>標籤: 當向資料庫傳送的請求中,【author】欄位不為空時,新增【author】欄位的查詢過濾條件 --> <if test="author != null"> and author = #{author} </if> </select>
-
測試實現類 => 【DaoTest】
@Test public void getBlogsByDynamicSQL(){ MyBatisUtils mybatis = new MyBatisUtils(); SqlSession sqlSession = mybatis.getSqlSession(); BlogsMapper mapper = sqlSession.getMapper(BlogsMapper.class); List<Blogs> blogs = mapper.getBlogsByDynaticSQL(); for (Blogs blog : blogs){ System.out.print(blog); } sqlSession.close(); }
1.2 where、set
-
【官方例項】
-
失敗案例
-
前面幾個例子已經合宜地解決了一個臭名昭著的動態 SQL 問題。現在回到之前的 “if” 示例,這次我們將 “state = ‘ACTIVE’” 設定成動態條件,看看會發生什麼。
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </select>
-
如果沒有匹配的條件會怎麼樣?最終這條 SQL 會變成這樣:
SELECT * FROM BLOG WHERE
-
這會導致查詢失敗。如果匹配的只是第二個條件又會怎樣?這條 SQL 會是這樣:
SELECT * FROM BLOG WHERE AND title like ‘someTitle’
-
-
成功案例
-
這個查詢也會失敗。這個問題不能簡單地用條件元素來解決。這個問題是如此的難以解決,以至於解決過的人不會再想碰到這種問題。MyBatis 有一個簡單且適合大多數場景的解決辦法。而在其他場景中,可以對其進行自定義以符合需求。而這,只需要一處簡單的改動:
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG <where> <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </where> </select>
-
-
-
【官方宣告】
-
<where>標籤:
- where 元素只會在子元素返回任何內容的情況下才插入 “WHERE” 子句。而且,若子句的開頭為 “AND” 或 “OR”,where 元素也會將它們去除。
-
<trim>標籤:
-
如果 where 元素與你期望的不太一樣,你也可以通過自定義 trim 元素來定製 where 元素的功能。比如,和 where 元素等價的自定義 trim 元素為:
//此案例實際上就是where這個標籤的工作原理,在拼接sql前方/開頭新增where,並去掉拼接語句整體最前方的and/or 單詞 <trim prefix="WHERE" prefixOverrides="AND |OR "> <!-- 【prefixOverrides】屬性:忽略通過管道符分隔的文字序列(注意此例中的空格是必要的)。會移除所有 prefixOverrides 屬性中指定的內容,並且插入 prefix 屬性中指定的內容。--> </trim>
-
-
<set>標籤:
-
用於動態更新語句的類似解決方案叫做 set。set 元素可以用於動態包含需要更新的列,忽略其它不更新的列。
<update id="updateAuthorIfNecessary"> update Author <set> <if test="username != null">username=#{username},</if> <if test="password != null">password=#{password},</if> <if test="email != null">email=#{email},</if> <if test="bio != null" >bio=#{bio}</if> </set> where id=#{id} </update>
-
-
1.2.1 測試
-
Dao層介面新增實現方法 => 【BlogsMapper】
int updateBlogInfoBySet(Map map);
-
XML對映檔案 => 【BlogsMapper.xml】
<update id="updateBlogInfoBySet" parameterType="blogs"> update test.blog <set> <if test="title != null"> title = #{title}</if> <if test="author != null"> author = #{author}</if> <if test="create_time != null"> create_time = #{createTime}</if> <if test="views != null"> views = #{views></if> </set> </update>
-
測試實現類 => 【DaoTest】
@Test public void dynamicSqlUpdateBySet(){ MyBatisUtils myBatisUtils = new MyBatisUtils(); SqlSession sqlSession = myBatisUtils.getSqlSession(); BlogsMapper mapper = sqlSession.getMapper(BlogsMapper.class); HashMap<String,String> map = new HashMap<String, String>(); map.put("title","updatedTitle"); map.put("author","updatedAuthor"); map.put("createTime", String.valueOf(new Date())); map.put("views","1"); map.put("id","5bde3e48b521443bb40524988456a668"); int i = mapper.updateBlogInfoBySet(map); if (i > 0 ){ System.out.println("Update Succeed!"); } sqlSession.close(); }
14.3 choose、when、otherwise
-
【官方宣告】:有時候,我們不想使用所有的條件,而只是想從多個條件中選擇一個使用。針對這種情況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 語句。
-
例子
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>
-
1.3.1 測試
1.3.1.1 環境搭建
-
dao層介面新增方法 => 【BlogsMapper】
List<Blogs> queryBlogsByChoose(Map map);
-
xml對映檔案 => 【BlogsMapper.xml】
//choose標籤類似於Java中的switch <select id="queryBlogsByChoose" resultType="blogs" parameterType="map"> select * from test.blog <!-- <choose>標籤: 選擇性返回 |- <when>標籤: 當其內部條件成立時返回 |- <otherwise>標籤: 當所有條件都不滿足時執行 --> <sql id="allchoose"> <where> <choose> <when test="title!=null"> title=#{title} </when> <when test="author!=null"> and author=#{author} </when> <otherwise> and views=5000 </otherwise> </choose> </where> </sql> <select id="queryBlogChoose" parameterType="map" resultType="blog"> select * from mybatis.blog <include refid="allchoose"></include> </select>
-
測試實現類 => 【DaoTest】 (按測試情況進行配置 )
14.3.1.2 測試結果
-
單個條件成立
-
測試實現類 => 【DaoTest】
@Test public void dynamicSqlChoose(){ MyBatisUtils myBatisUtils = new MyBatisUtils(); SqlSession sqlSession = myBatisUtils.getSqlSession(); BlogsMapper mapper = sqlSession.getMapper(BlogsMapper.class); HashMap<String,String> map = new HashMap<String, String>(); //建立單條件成立的集合 map.put("title","MyBatis"); System.out.println(mapper.queryBlogsByChoose(map)); sqlSession.close(); }
-
-
多個條件成立
-
測試實現類 => 【DaoTest】
@Test public void dynamicSqlChoose(){ MyBatisUtils myBatisUtils = new MyBatisUtils(); SqlSession sqlSession = myBatisUtils.getSqlSession(); BlogsMapper mapper = sqlSession.getMapper(BlogsMapper.class); HashMap<String,String> map = new HashMap<String, String>(); //建立多個條件滿足的集合 map.put("title","MyBatis"); map.put("author","Camelot"); System.out.println(mapper.queryBlogsByChoose(map)); sqlSession.close(); }
-
-
<when>都為false,<otherwise>為true
-
測試實現類 => 【DaoTest】
@Test public void dynamicSqlChoose(){ MyBatisUtils myBatisUtils = new MyBatisUtils(); SqlSession sqlSession = myBatisUtils.getSqlSession(); BlogsMapper mapper = sqlSession.getMapper(BlogsMapper.class); //建立空集合傳入 HashMap<String,String> map = new HashMap<String, String>(); System.out.println(mapper.queryBlogsByChoose(map)); sqlSession.close(); }
-
-
結論
<choose>標籤會在多個條件都滿足的情況下,僅會返回第一個傳參的返回值。
但當其他條件都不滿足時,可以新增<otherwise>標籤,用於返回一個固有值。
14.4 Trim
- Trim可以自定義SQL語句中的規範,當<where>標籤、<set>標籤不滿足時,可以使用Trim自定義。
14.4.1 Trim自定義測試
- 使用Trim複寫<where>、<set>規則
14.4.1.1 <trim>實現<where>
-
Dao層介面 => 【BlogsMapper】
List<Blogs> queryBlogsByTrim(Map<String,String> map)
-
XML對映器 => 【BlogsMapper.xml】
<select id="queryBlogsByTrim" parameterType="blogs"> select * from test.blog <trim prefix="WHERE" prefixOverride="AND |OR ">//prefix去字首 <if test="titleMap != null"> AND title = #{titleMap}</if> <if test="authorMap != null"> OR author = #{authorMap}</if> </trim> </select>
-
測試實現類 => 【DaoTest】
@Test public void dynamicSqlSelectByTrim(){ MyBatisUtils mybatis = new MyBatisUtils; SqlSession sqlSession = mybatis.getSqlSession(); BlogsMapper mapper = sqlSession.getMapper(BlogsMapper.class); HashMap<String,String> map = new HashMap<String,String>(); map.put("titleMap","MyBatis"); map.put("authorMap","Altria"); for (Blogs blog : mapper.queryBlogsByTrim(map)) { System.out.println(blog); } sqlSession.close(); }
1.4.1.2 <trim>實現<set>
-
Dao層介面 => 【BlogsMapper】
int updateBlogInfoByTrim(Map<String,String> map)
-
XML對映檔案 => 【BlogsMapper.xml】
<update id="updateBlogInfoByTrim" parameterType="map"> update test.blog <trim prefix="SET" suffixOverride=",">//suffix去後綴 <if test="titleMap != null"> title = #{titleMap},</if> <if test="authorMap != null"> author = #{authorMap},</if> </trim> where id = #{idMap} </update>
-
測試實現類 => 【DaoTest】
@Test public void dynamicSqlUpdateByTrim(){ MyBatisUtils mybatis = new MyBatisUtils(); SqlSession sqlSession = mybatis.getSqlSession(); BlogsMapper mapper = mybatis.getMapper(BlogsMapper.class); Map<String,String> map = new HashMap<String,String>(); map.put("authorMap","Altria"); map.put("titleMap","Spring Framework Updated"); map.put("idMap","5aa45402bc764755b3ae406be6b27d33"); int i = mapper.updateBlogInfoByTrim(map); if( i > 0 ){ System.out.println("Update Succeed!"); } }