1. 程式人生 > 實用技巧 >11.動態sql

11.動態sql

11.動態sql

什麼是動態sql?

  • 動態 SQL 是 MyBatis 的強大特性之一。

  • 在 MyBatis 之前的版本中,需要花時間瞭解大量的元素。藉助功能強大的基於 OGNL 的表示式,MyBatis 3 替換了之前的大部分元素,大大精簡了元素種類,現在要學習的元素種類比原來的一半還要少。

    • if

    • choose (when, otherwise)

    • trim (where, set)

    • foreach

11.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(30) NOT NULL COMMENT '瀏覽量'
)ENGINE=INNODB DEFAULT CHARSET=utf8


INSERT INTO blog VALUES('1','設計模式之單例模式','xuan',CURRENT_DATE,100);
INSERT INTO blog VALUES('2','設計模式之工廠模式','xuan',CURRENT_DATE,200);
INSERT INTO blog VALUES('3','設計模式之建立者模式','xuan',CURRENT_DATE,300);
INSERT INTO blog VALUES('4','設計模式之抽象工廠模式','xuan',CURRENT_DATE,400);
INSERT INTO blog VALUES('5','設計模式之責任鏈模式','xuan',CURRENT_DATE,1000);
INSERT INTO blog VALUES('6','設計模式之橋接模式','xuan',CURRENT_DATE,50);

第二步:匯入依賴、編寫實體類,介面以及對應的配置檔案

<dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!--mysql資料庫驅動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<!--junit測試-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
</dependencies>
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog implements Serializable {

private String id;
private String title;
private String author;
private Date createTime;
private Integer views;
}
public interface BlogMapper {
}
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xuan.mapper.BlogMapper">

</mapper>

11.2 IF語句

  • 使用動態 SQL 最常見情景是根據條件包含 where 子句的一部分

第一步:編寫mapper介面

public interface BlogMapper {

//通過if條件查詢所需資訊
List<Blog> findBlogByIf(Map<String,Object> map)throws Exception;
}

第二步:編寫配置 加上if條件

<select id="findBlogByIf" 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>

第三步:編寫測試map為空返回全部

@Test
public void testFindBlogByIf() throws Exception {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

Map<String, Object> map = new HashMap<>();

List<Blog> blogs = mapper.findBlogByIf(map);

for (Blog blog : blogs) {
System.out.println(blog);
}

sqlSession.close();
}
  • 測試結果

Blog(id=1, title=設計模式之單例模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=100)
Blog(id=2, title=設計模式之工廠模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=200)
Blog(id=3, title=設計模式之建立者模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=300)
Blog(id=4, title=設計模式之抽象工廠模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=400)
Blog(id=5, title=設計模式之責任鏈模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=1000)
Blog(id=6, title=設計模式之橋接模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=50)

第四步:測試加上if判斷的語句

@Test
public void testFindBlogByIf() throws Exception {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

Map<String, Object> map = new HashMap<>();
map.put("title","設計模式之建立者模式");
map.put("author","xuan");

List<Blog> blogs = mapper.findBlogByIf(map);

for (Blog blog : blogs) {
System.out.println(blog);
}

sqlSession.close();
}
  • 測試結果

Blog(id=3, title=設計模式之建立者模式, author=xuan, createTime=Tue Jul 14 08:00:00 GMT+08:00 2020, views=300)

11.3 choose、when、otherwise語句

  • 有時候,我們不想使用所有的條件,而只是想從多個條件中選擇一個使用。

第一步:編寫mapper介面

//通過choose條件查詢所需資訊
List<Blog> findBlogByChoose(Map<String,Object> map)throws Exception;

第二步:編寫配置檔案(加入choose判斷語句)

<select id="findBlogByChoose" parameterType="map" resultType="blog">
select * from blog where author="xuan"
<choose>
<when test="title != null">
and title=#{title}
</when>
<when test="views != null">
and views=#{views}
</when>
<otherwise>
and id=1
</otherwise>
</choose>
</select>

第三步:編寫測試

@Test
public void testFindBlogByChoose() throws Exception {
SqlSession sqlSession = MyBatisUtil.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

Map<String, Object> map = new HashMap<>();
//map.put("title","設計模式之建立者模式");
map.put("views",100);

List<Blog> blogs = mapper.findBlogByChoose(map);

for (Blog blog : blogs) {
System.out.println(blog);
}

sqlSession.close();
}

--------------------------------------測試成功------------------------------------

11.4 trim、where、set語句

  • where標籤作用:where 元素只會在子元素返回任何內容的情況下才插入 “WHERE” 子句。而且,若子句的開頭為 “AND” 或 “OR”,where 元素也會將它們去除。

<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>
  • 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>
  • trim標籤:prefixOverrides 屬性會忽略通過管道符分隔的文字序列(注意此例中的空格是必要的)。上述例子會移除所有 prefixOverrides 屬性中指定的內容,並且插入 prefix 屬性中指定的內容。

<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<trim prefix="SET" suffixOverrides=",">
...
</trim>

11.5 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)變數。

  • 它也允許你指定開頭與結尾的字串以及集合項迭代之間的分隔符( open="(" separator="," close=")">)。這個元素也不會錯誤地新增多餘的分隔符

完整的sql: select * from blog where id in (1 or 2 or 3)

<select id="findByForEach" resultType="blog" parameterType="map">
select * from blog
<where>
<foreach item="id" index="index" collection="ids"
open="(" separator="or" close=")">
id = #{id}
</foreach>
</where>
</select>

11.6 SQL片段

為什麼要寫SQL片段?

  • 主要是可以實現程式碼複用,有些重複的sql抽取出來重複使用。

  • sql標籤: 通過id用來存放可重複利用的片段

  • include標籤:refid用來引入sql標籤中的語句

<select id="findBlogByIf" parameterType="map" resultType="blog">
select * from blog
<where>
<include refid="sql-if"></include>
</where>
</select>

<sql id="sql-if">
<if test="title != null">
and title=#{title}
</if>
<if test="author != null">
and author=#{author}
</if>
</sql>