MyBatis動態SQL--簡化SQL語句的利器

爲什麼要學MyBatis的動態SQL?

在執行sql語句時,不免會有一些很常用但是寫起來又很複雜的SQL語句,使用了動態SQL就能把這些sql語句封裝,只需要寫簡短的代碼就能替換冗餘的sql語句,並且在修改這些重組的SQL語句時,因爲進行了封裝,就能只修改一份就可以,減少出錯的可能

今天沒有重點 ,全是重點和乾貨

動態SQL

MyBatis的映射文件中支持在基礎SQL上添加一些邏輯操作,並動態拼接成完整的sql之後再執行,以達到SQL複用,簡化編程的效果

sql標籤

對兩個查詢方法中相同的sql語句用sql進行了封裝

兩個查詢方法
image-20200617083150684
  • 這兩個方法都需要查詢的是該課程的全部信息和屬於該課程的學生的信息,只是查詢的方式不同,一個是通過id,另一個通過name
   <sql id="subject_all">
        select t_subjects.id,t_subjects.name,t_subjects.grade,t_students.id stu_id,t_students.name stu_name,t_students.sex
        from t_subjects join t_stu_sub
        on t_subjects.id = t_stu_sub.subject_id
        join t_students
        on t_students.id = t_stu_sub.student_id
    </sql>

    <select id="querySubjectById" resultMap="Subject_map">
        <include refid="subject_all"></include>
        where t_subjects.id=#{id}
    </select>


    <select id="querySubjectByName" resultMap="Subject_map">
        <include refid="subject_all"/>
        where t_subjects.name =#{name}
    </select>
  • 通過標籤能抽取到重複的sql語句,簡化代碼書寫,在業務邏輯發生改變時,修改代碼時只需要修改sql標籤中的sql語句就可以,不需要重複修改大量的sql語句
查詢結果
image-20200617083238203

if標籤

另外對於查詢方法而言,我們可能需要很多的查詢方法,如果我們爲每個方法都定義一個Dao的方法,那麼我們的方法就會很多,MyBatis允許我們把這些特別相似的方法合併爲一個方法

對於前面這兩個方法,我們通過MyBatis來做合併方法

SubjectDao
image-20200617090326409

mapper映射文件

<!--    <select id="querySubjectById" resultMap="Subject_map">-->
<!--        <include refid="subject_all"></include>-->
<!--        where t_subjects.id=#{id}-->
<!--    </select>-->


<!--    <select id="querySubjectByName" resultMap="Subject_map">-->
<!--        <include refid="subject_all"/>-->
<!--        where t_subjects.name =#{name}-->
<!--    </select>  
<!-- MyBatis動態sql的方法合併-->
    <!-- 這裏因爲我們查詢的參數是一個Subject的對象,我們需要通過對象的屬性來查詢
    我們約定要通過那個屬性查詢,那麼就只(只給這一個屬性賦值)的方式來查詢 -->
    <select id="querySubjectBySubject" resultMap="Subject_map">
        <include refid="subject_all"/>
        where
        <if test="id!=null">
            t_subjects.id=#{id}
        </if>
        <if test="name!=null">
            t_subjects.name = #{name}
        </if>

    </select>
  • 需要注意的: if便籤中的test屬性中的id!=null就相當於我們的#{id}!=null,也就是取類中的屬性,只是在test的屬性中我們不需要那麼寫.實際意義是相同的

測試類代碼

測試類
image-20200617090434665

結果輸出

查詢結果
image-20200617090610235

我們這個實例中使用的查詢方法默認的是隻有一個屬性被賦值

然後我們只查詢那個被賦值的屬性(另一個屬性沒有被賦值,爲空)

那麼如果屬性都不爲空呢?

也就是查詢這個屬性或者通過另一個屬性查詢

 //根據Subject類對象的屬性查詢該課程的全部信息和屬於該課程的學生的信息
    List<Subject> querySubject(Subject subject);
    //不論提供的屬性是否賦值,只要是賦值的屬性都會根據查詢   也就是關係中的or

  • 由於得到的對象可能不是一個,這裏需要定義爲集合類型
    <select id="querySubject" resultMap="Subject_map">
        <include refid="subject_all"/>
        where
        <if test="id!=null">
            t_subjects.id=#{id}
        </if>
        <if test="name!=null">
           or  t_subjects.name = #{name}
        </if>
    </select>
  • 注意if中使用了or來控制mybatis的查詢可以基於兩個不同的屬性

測試類部分代碼

        Subject subject3 = new Subject(1001,"JavaEE",null);

        List<Subject> subjects = mapper.querySubject(subject3);
        for (Subject subject4 :
                  subjects      ) {
            System.out.println(subject4);
        }
查詢結果
image-20200617093951488

不僅查詢出了id值爲1001的數據,也查詢出了name值爲JavaEE的屬性

  • 需要注意的是使用or關鍵字來實現了或關係的查詢中,在文件映射中寫的sql語句中關於對象的屬性寫在後面的屬性可以爲空
  • 其中and關鍵字實現的關聯查詢也可以用if標籤實現
賦值注意事項
image-20200617094557393

那麼怎麼解決這樣的問題:

where標籤

使用where標籤,就能夠解決or關鍵字異常注入的問題

  1. 補充where關鍵字
  2. 識別where子句中如果以or(and)開頭 那麼會去掉or(或者and)
  <select id="querySubject" resultMap="Subject_map">
      <include refid="subject_all"/>
      <where>
          <if test="id!=null">
              t_subjects.id=#{id}
          </if>
          <if test="name!=null">
              or t_subjects.name = #{name}
          </if>
      </where>
     
  </select>
  • 使用where標籤而不是數據庫中的where關鍵字

使用了where標籤之後我們將要賦值的第一個參數賦值爲null,測試是否會報錯

        System.out.println(">>>>>>>>>>>>>>>>>>>>");
        Subject subject3 = new Subject(null,"JavaEE",null);

        List<Subject> subjects = mapper.querySubject(subject3);
        for (Subject subject4 :
                  subjects      ) {
            System.out.println(subject4);
        }
查詢結果(沒有報錯,成功查詢到數據)
image-20200617095259021

set標籤

  1. 補充set
  2. 自動將set子句的最後的逗號去除

如果不使用set標籤的話:

如果我們的更新操作中.所有的屬性列都不賦值爲null(即所有的屬列都進行賦值),那麼不會出現問題,但是如果有屬性列不進行賦值那麼後面的逗號會注入到sql語句中造成語法錯誤

更新操作中不使用set標籤造成的逗號的注入
image-20200617104300347

使用了標籤,如果該列不想進行賦值更新,那麼標籤會自動的將逗號去除

trim標籤

trim標籤可以替換掉where標籤和set標籤的功能

比如替換where

原來的where標籤實現的功能

    <select id="querySubject" resultMap="Subject_map">
        <include refid="subject_all"/>
        <where>
            <if test="id!=null">
                t_subjects.id=#{id}
            </if>
            <if test="name!=null">
                or t_subjects.name = #{name}
            </if>
        </where>

    </select>

用trim標籤替換where標籤

    <select id="querySubject" resultMap="Subject_map">
        <include refid="subject_all"/>
        <trim prefix="where" perfixOverrides="and|or" 
            <if test="id!=null">
                t_subjects.id=#{id}
            </if>
            <if test="name!=null">
                or t_subjects.name = #{name}
            </if>
		</trim>
    </select>

原來的set標籤實現的功能

    <update id="querySubject" resultMap="Subject_map">
        <include refid="subject_all"/>
        <set>
            <if test="id!=null">
                t_subjects.id=#{id}
            </if>
            <if test="name!=null">
                or t_subjects.name = #{name}
            </if>
        </set>

    </update>

用trim標籤替換set標籤

    <update id="querySubject" resultMap="Subject_map">
        <include refid="subject_all"/>
        <trim prefix="set"suffixOverrides=",">
            <if test="id!=null">
                t_subjects.id=#{id}
            </if>
            <if test="name!=null">
                or t_subjects.name = #{name}
            </if>
        </trim>

    </update>

foreach標籤

標籤的作用是支持一些批量的操作,批量的添加,批量的刪除,以及一些批量的更新

<delect id="deleteSubjects" >
    DELETE FROM t_subjects
    WHERE id IN
    <foreach collection="list" open="(" separator=","close=")" item="id" index="i">
    </foreach>
</delect>
參數 描述 取值
collection 容器類型 list.array.map
open 起始符 (
close 結束符 )
separator 分隔符 ,
index 下標符 從0開始,依次遞增
item 當前項 任意名稱(循環中通過#{任意名稱}表達式訪問)
<delect id="deleteSubjects" parameterType="java.util.List">
    DELETE FROM t_subjects
    WHERE t_subjects.id IN
    <foreach collection="list" open="(" separator="," close=")" item="id">
        #{id}
    </foreach>
</delect>

測試類

  System.out.println("<<<<<<<<<<<<<<<<<<");
        List<Integer> ids = Arrays.asList(1005, 1006);
        mapper.deleteSubjects(ids);
        MybatisUtil.commit();
批量刪除結果
image-20200617114647621

我是雷雨佳,一個普本科的學生,主要專注於Java後端和大數據開發

如果這篇文章有幫助到你,希望你給我一個大大的贊
如果有什麼問題,希望你能留言和我一起研究,學習靠自覺,分享靠自願

轉載註明出處
https://blog.csdn.net/qq_40742223

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章