MyBatis-06-動態SQL
阿新 • • 發佈:2020-11-10
十、動態SQL
- 什麼是動態SQL?
- 根據給出引數的不同,通過拼接等操作,生成不同的SQL語句
10.1 構造實驗環境
-
資料庫設計
CREATE TABLE `blog` ( `id` varchar(50) NOT NULL COMMENT '部落格id', `title` varchar(100) NOT NULL COMMENT '部落格標題', `author` varchar(30) NOT NULL COMMENT '部落格作者', `create_time` datetime NOT NULL COMMENT '建立時間', `views` int NOT NULL COMMENT '瀏覽量' ) ENGINE=InnoDB DEFAULT CHARSET=utf8
-
mybatis-config.xml
<settings> <!--開啟日誌以及自動轉換駝峰命名--> <setting name="logImpl" value="STDOUT_LOGGING"/> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>
-
實體類
package com.pbx.pojo; import java.util.Date; /** * @author BruceXu * @date 2020/11/8 */ public class Blog { private String id; private String title; private String author; private Date createTime; private int views; }
-
id工具類
package com.pbx.utils; import java.util.UUID; /** * @author BruceXu * @date 2020/11/8 */ public class IDUtils { public static String getId() { return UUID.randomUUID().toString().replaceAll("-",""); } }
-
BlogMapper介面
package com.pbx.mapper; import com.pbx.pojo.Blog; import org.apache.ibatis.annotations.Insert; /** * @author BruceXu * @date 2020/11/8 */ public interface BlogMapper { @Insert("insert into blog (id, title, author, create_time, views) values (#{id},#{title},#{author},#{createTime},#{views});") int addBlog(Blog blog); }
-
插入資料
@Test public void addBlog() { SqlSession session = MyBatisUtils.getSqlSession(); BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = new Blog(); blog.setId(IDUtils.getId()); blog.setTitle("Mybatis如此簡單"); blog.setAuthor("BruceXu"); blog.setCreateTime(new Date()); blog.setViews(9999); mapper.addBlog(blog); blog.setId(IDUtils.getId()); blog.setTitle("Java如此簡單"); mapper.addBlog(blog); blog.setId(IDUtils.getId()); blog.setTitle("Spring如此簡單"); mapper.addBlog(blog); blog.setId(IDUtils.getId()); blog.setTitle("微服務如此簡單"); mapper.addBlog(blog); blog.setId(IDUtils.getId()); blog.setTitle("狂神說Java真的好"); mapper.addBlog(blog); session.commit(); session.close(); }
10.2 if
-
這個if和高階語言裡面的判斷語句if是一樣的功能
-
需求
- 根據author和title來查詢部落格,如果一個為空,則就按照另外一個進行查詢
-
BlogMapper介面
List<Blog> getBlog(Map map);
-
BlogMapper.xml
<mapper namespace="com.pbx.mapper.BlogMapper"> <select id="getBlog" parameterType="map" resultType="Blog"> select * from blog where 1=1 <if test="title != null"> and title = #{title} </if> <if test="author != null"> and author = #{author} </if> </select> </mapper>
-
測試
@Test public void getBlog() { SqlSession session = MyBatisUtils.getSqlSession(); BlogMapper mapper = session.getMapper(BlogMapper.class); Map<String, String> map = new HashMap<>(); // map.put("title", "Mybatis如此簡單"); // map.put("author", "BruceXu"); List<Blog> blogList = mapper.getBlog(map); for (Blog blog : blogList) { System.out.println(blog); } session.close(); }
-
如果說if中的條件有滿足的話,則拼接上SQL語句如果沒有滿足的話,則不進行拼接
10.3 choose (when, otherwise)
-
choose的作用類似於高階語言中的switch~case語句塊
-
需求:根據author或title來查詢部落格,有誰查誰,如果都沒有就按照views查詢
-
BlogMapper介面
List<Blog> getBlog2(Map map);
-
BlogMapper.xml
<mapper> <select id="getBlog2" parameterType="map" resultType="Blog"> select * from blog where 1=1 <choose> <when test="title != null"> and title = #{title} </when> <when test="author != null"> and author = #{author} </when> <otherwise> and views = 9999 </otherwise> </choose> </select> </mapper>
-
測試
@Test public void getBlog2() { SqlSession session = MyBatisUtils.getSqlSession(); BlogMapper mapper = session.getMapper(BlogMapper.class); Map<String, String> map = new HashMap<>(); // map.put("title", "Java如此簡單"); // map.put("author", "BruceXu"); List<Blog> blogList = mapper.getBlog2(map); for (Blog blog : blogList) { System.out.println(blog); } session.close(); }
-
可以看到,如果when中的條件沒有一個匹配上,那麼拼接上otherwise中的內容。如果when中有多個匹配,那麼則只拼接第一個匹配的
10.4 trim (where, set)
-
如果仔細看上面兩個測試環境中使用的SQL語句,都會發現存在這麼一點
where 1=1
,這個是為了保證在進行拼接的時候不出現這樣的錯誤:select * from blog where and author = ...
-
那麼有沒有這樣的一種方法,能夠自動判斷是不是要加上and或者空格等符號以保證SQL語句的正確性?
-
trim標籤,當然,MyBatis也為我們提前封裝好了where和set標籤
<trim prefix="字首匹配" prefixOverrides="字首替換" suffix="字尾匹配" suffixOverrides="字尾替換">...</trim>
-
where和set示例
- BlogMapper介面
List<Blog> getBlog3(Map map); int updateBlog(Map map);
- BlohMapper.xml
<mapper> <select id="getBlog3" parameterType="map" resultType="Blog"> select * from blog <where> <if test="title != null"> and title = #{title} </if> <if test="author != null"> and author = #{author} </if> </where> </select> <update id="updateBlog" parameterType="map"> update blog <set> <if test="title != null"> title = #{title}, </if> <if test="author != null"> author = #{author}, </if> <if test="view != null"> views = #{view}, </if> </set> </update> </mapper>
- 測試
@Test public void getBlog3() { SqlSession session = MyBatisUtils.getSqlSession(); BlogMapper mapper = session.getMapper(BlogMapper.class); Map<String, String> map = new HashMap<>(); // map.put("title", "Mybatis如此簡單"); map.put("author", "BruceXu"); List<Blog> blog3 = mapper.getBlog3(map); for (Blog blog : blog3) { System.out.println(blog); } session.close(); } @Test public void updateBlog() { SqlSession session = MyBatisUtils.getSqlSession(); BlogMapper mapper = session.getMapper(BlogMapper.class); Map<String, String> map = new HashMap<>(); map.put("view", "6666"); map.put("id", "ccfb770fc1b64dbf8fd7379a564dcd9f"); map.put("title", "狂神Java說的是真的好"); mapper.updateBlog(map); List<Blog> blog3 = mapper.getBlog3(map); for (Blog blog : blog3) { System.out.println(blog); } session.commit(); session.close(); }
- 可以看到,MyBatis都幫助我們成功的完成了SQL拼接,並沒有出現任何錯誤
10.5 SQL片段
-
有些時候,在業務的處理過程中,可能某一部分SQL語句使用比較頻繁,所以我們可以將其抽取出來,單獨成為一個片段。然後在需要的使用通過
<include>
標籤匯入即可 -
提取SQL片段
<sql id="if-title-author"> <if test="title != null"> title = #{title} </if> <if test="author != null"> and author = #{author} </if> </sql>
-
引用SQL片段
<select id="queryBlogIf" parameterType="map" resultType="blog"> select * from blog <where> <!-- 引用 sql 片段,如果refid 指定的不在本檔案中,那麼需要在前面加上 namespace--> <include refid="if-title-author" /> <!-- 在這裡還可以引用其他的 sql 片段 --> </where> </select>
10.6 foreach
- 動態 SQL 的另一個常見使用場景是對集合進行遍歷(尤其是在構建 IN 條件語句的時候)。比如:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
-
foreach 元素的功能非常強大,
- 它允許你指定一個集合,宣告可以在元素體內使用的集合項(item)和索引(index)變數。
- 它也允許你指定開頭與結尾的字串以及集合項迭代之間的分隔符。這個元素也不會錯誤地新增多餘的分隔符,
-
提示
- 你可以將任何可迭代物件(如 List、Set 等)、Map 物件或者陣列物件作為集合引數傳遞給 foreach。
- 當使用可迭代物件或者陣列時,index 是當前迭代的序號,item 的值是本次迭代獲取到的元素。
- 當使用 Map 物件(或者 Map.Entry 物件的集合)時,index 是鍵,item 是值。