MyBatis筆記(六)

linzeliang發表於2021-04-13

1. 動態SQL

1.1 介紹

  • 概念:**動態SQL指的是根據不同的查詢條件 , 生成不同的Sql語句.*

    官網描述:
    MyBatis 的強大特性之一便是它的動態 SQL。如果你有使用 JDBC 或其它類似框架的經驗,你就能體會到根據不同條件拼接 SQL 語句的痛苦。例如拼接時要確保不能忘記新增必要的空格,還要注意去掉列表最後一個列名的逗號。利用動態 SQL 這一特性可以徹底擺脫這種痛苦。
    雖然在以前使用動態 SQL 並非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 對映語句中的強大的動態 SQL 語言得以改進這種情形。
    動態 SQL 元素和 JSTL 或基於類似 XML 的文字處理器相似。在 MyBatis 之前的版本中,有很多元素需要花時間瞭解。MyBatis 3 大大精簡了元素種類,現在只需學習原來一半的元素便可。MyBatis 採用功能強大的基於 OGNL 的表示式來淘汰其它大部分元素。


      - if
      - choose (when, otherwise)
      - trim (where, set)
      - foreach
      -------------------------------
    

1.2 搭建環境

  1. 新建一個表:blog

    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;
    
  2. 外掛IDUtil工具類

    public class IDUtil {
        public static String genId(){
            return UUID.randomUUID().toString().replaceAll("-","");
        }
    }
    
  3. 編寫實體類

    public class Blog {
        private String id;
        private String title;
        private String author;
        private Date createTime;
        private int views;
        
        // 無參構造
        // 有參構造
        // get、set、toString
    }
    
  4. 編寫Mapper介面及mapper配置檔案

    public interface BlogMapper {
        int addBlog(Blog blog);
    }
    
    <?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="top.linzeliang.mapper.BlogMapper">
        <insert id="addBlog" parameterType="blog">
            insert into blog (id, title, author, create_time, views)
            values (#{id},#{title},#{author},#{createTime},#{views});
        </insert>
    </mapper>
    
  5. 在MyBatis配置檔案中設定下駝峰線自動轉換

    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!--註冊Mapper.xml-->
    <mappers>
        <mapper resource="top/linzeliang/mapper/BlogMapper.xml"/>
    </mappers>
    
  6. 初始化部落格方法

    @Test
    public void addInitBlog(){
        SqlSession session = MybatisUtils.getSession();
        BlogMapper mapper = session.getMapper(BlogMapper.class);
    
        Blog blog = new Blog();
        blog.setId(IDUtil.genId());
        blog.setTitle("Mybatis如此簡單");
        blog.setAuthor("妙啊");
        blog.setCreateTime(new Date());
        blog.setViews(9999);
    
        mapper.addBlog(blog);
    
        blog.setId(IDUtil.genId());
        blog.setTitle("Java如此簡單");
        mapper.addBlog(blog);
    
        blog.setId(IDUtil.genId());
        blog.setTitle("Spring如此簡單");
        mapper.addBlog(blog);
    
        blog.setId(IDUtil.genId());
        blog.setTitle("微服務如此簡單");
        mapper.addBlog(blog);
    
        session.close();
    }
    

2. IF和WHERE語句

  • if語句就是判斷是否滿足某個條件,滿足的話就新增標籤內容到sql語句中
  • where語句:如果包含的標籤中含有返回值得話,他就會自動插入一個where,如果返回值的內容的第一個開頭是 and 或者 or,則會自動剔除

需求:根據作者名字和部落格名字來查詢博,如果作者名字為空,那麼只根據部落格名字查詢,反之,則根據作者名來查詢

  1. 編寫介面類

    List<Blog> queryBlogIf(Map map);
    
  2. 編寫對應的mapper配置檔案

    • 傳入的引數是map,那麼在if標籤中直接寫的是map中的key,不用加#{}
    <select id="queryBlogIf" resultType="blog" parameterType="map">
        select *
        from blog
        <where>
            <if test="title != null">
                and title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>
    </select>
    

3. SET語句

  • 如果在進行更新操作的時候,含有 set 關鍵詞,則使用set標籤,效果和where也是一樣的
  1. 編寫介面方法

    int updateBlog(Map map);
    
  2. 編寫對應的mapper配置檔案

    <update id="updateBlog" parameterType="map">
        update blog
        <set>
            <if test="title != null">
                title = #{title},
            </if>
            <if test="author != null">
                author = #{author}
            </if>
        </set>
        where id = #{id}
    </update>
    

4. CHOOSE語句

  • 有時候,我們不想用到所有的查詢條件,只想選擇其中的一個,查詢條件有一個滿足即可,使用 choose 標籤可以解決此類問題,類似於 Java 的 switch 語句
  1. 編寫介面方法

    List<Blog> queryBlogChoose(Map map);
    
  2. 編寫對應的mapper配置檔案

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

5. SQL片段

  • 有時候可能某個 sql 語句我們用的特別多,為了增加程式碼的重用性,簡化程式碼,我們需要將這些程式碼抽取出來,然後使用時直接呼叫

  • 提取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"></include>
            <!-- 在這裡還可以引用其他的 sql 片段 -->
        </where>
    </select>
    
  • 最好基於 單表來定義 sql 片段,提高片段的可重用性

  • 在 sql 片段中不要包括 where

6. ForEach

需求:我們需要查詢 blog 表中 id 分別為1,2,3的部落格資訊

  1. 編寫介面

    List<Blog> queryBlogForeach(Map map);
    
  2. 編寫對應的mapper配置檔案

    <select id="queryBlogForeach" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <!--
                collection:指定輸入物件中的集合屬性
                item:每次遍歷生成的物件
                open:開始遍歷時的拼接字串
                close:結束時拼接的字串
                separator:遍歷物件之間需要拼接的字串
                select * from blog where 1=1 and (id=1 or id=2 or id=3)
           -->
            <foreach collection="ids"  item="id" open="and (" close=")" separator="or">
                id = #{id}
            </foreach>
        </where>
    </select>
    
  3. 總結:其實動態sql語句的編寫往往就是一個拼接的問題,為了保證拼接準確,我們最好首先要寫原生的sql語句出來,然後在通過mybatis動態sql對照著改,防止出錯

相關文章