Mybatis 輸入輸出映射和動態SQL

Mybatis 輸入輸出映射和動態SQL

輸入映射

輸入的元素可以是簡單類型, pojo 對象,也可以是map

如果查詢的判斷條件很複雜,這時我們一般採用pojo對象來封裝需要的判斷元素,將封裝好的pojo對象,傳入

輸出映射

輸出的元素可以是簡單類型, pojo 對象,也可以是map

  • 輸出映射可以採用 resultType 進行映射, 指定返回的對象,但是使用此有幾個限制:

使用resultType進行輸出映射,只有查詢出來的列名和返回的pojo對象中的屬性名一致,該列纔可以映射成功。

如果查詢出來的列名和pojo中的屬性名全部不一致,沒有創建pojo對象。

只要查詢出來的列名和pojo中的屬性有一個一致,就會創建pojo對象。

  • 使用 resultMap 完成高級輸出結果映射
    如果查詢出來的列名和pojo的屬性名不一致,通過定義一個resultMap對列名和pojo屬性名之間作一個映射關係。

1、定義resultMap

2、使用resultMap作爲statement的輸出映射類型

<!-- id 爲 此resultMap 的唯一標識,在下面的select 語句中 的 resultMap 處使用,
 type 爲Java編寫的返回的pojo對象的引用,此處使用的是別名,別名在sqlMapConfig中定義-->
<resultMap id="UserCustomer" type="UserCustomer">
    <id property="customer_id" column="id"/>
    <result property="customer_username" column="username"/>
    <result property="customer_address" column="address"/>
    <result property="customer_sex" column="sex"/>
    <result property="customer_birthday" column="birthday"/>
</resultMap>
<!--使用動態字符串拼接-->
    <select id="queryUserByUserQueryVo" parameterType="com.dustin.dao.UserQueryVo" resultMap="UserCustomer">
        select * from User
        <where>
            <!-- 判斷條件是什麼-->
            <if test="user.username != null and user.username != ''">
                    and username = #{user.username}
            </if>
            <if test="user.sex != null and user.sex != ''">
                    and sex = #{user.sex}
            </if>
            <!-- collection 是傳進來的參數名稱, item 是當前變量, open 是語句以什麼開頭,
             close 是以什麼結尾, separator 是遍歷每一個元素的分隔符-->
            <if test="ids != null">
                <foreach collection="ids" item="id" open=" and id in (" close=")" separator=",">
                    #{id}
                </foreach>
            </if>
        </where>
    </select>

級聯功能

這個功能是幹什麼的呢, 比如 我們要查用戶的個人信息,以及他的訂單信息,個人信息在一個表中, 訂單信息在一個表中,則需要返回的resultMap 中則會有一個訂單信息 List , 如何根據用戶id查詢訂單信息並將訂單信息填充到 resultMap中呢? 此時級聯功能可以起到作用。

mybatis 中級聯分爲三種:

* association 代表一對一的關係 *
* collection 代表一對多的關係 *
* discriminator 鑑別器,根據條件選擇哪個類作爲實例*

<resultMap>
.....
<!-- 含義property 爲返回的pojo對象中的變量名
 column 爲 傳入的條件字段,多個字段可以要給你逗號隔開
 select 爲 要執行的SQL語句,一般是要執行的方法的引用 -->
 <!-- 1:1 -->
<association property = 'studentSelfcard' column = 'id' select = 'com.learn.mapper.studentSelfcard.ffindStudentSelfcardbystudentId'/>

<!-- 1:N -->
<collection property = '' column = '' select = ''/>


<!-- 鑑別器 分爲兩步, 第一步先說明,給出選擇條件 -->
<discriminator javaType = "int" coloum = 'sex'>
<case value = '1' resultMap = "maleStudentMap"/>
<case value = '2' resultMap = "femaleStudentMap"/>
</discriminator>
<!-- id 爲上面進行選擇的唯一標識
type 爲返回的查詢結果對應的類
extends 繼承id爲studentMap的映射配置 -->
<resultMap id = "maleStudentMap" type = "XX.XX.XX.maleStudentBean"  extends = "studentMap">
</resultMap>
<resultMap id = "femaleStudentMap" type = "XX.XX.XX.maleStudentBean"  extends = "studentMap">
</resultMap>

級聯的缺陷 性能上會出現N+1問題

N+1 問題:

  1. 你執行了一個單獨的 SQL 語句來獲取結果列表(就是“+1”)。
  2. 對返回的每條記錄,你執行了一個查詢語句來爲每個加載細節(就是“N”)。

這個問題會導致成百上千的 SQL 語句被執行。這通常不是期望的。

Mybatis 的解決方案: 延遲加載 能大大提高數據庫的性能,因爲單標查詢的速度要比多表查詢快

兩個參數:

設置 lazzyLoadingEnabled = true 開啓延遲加載功能

設置 aggeressiveLazzyLoading = false 將代表着 延遲加載下的 按需加載,即調用時纔會進行加載

如果只設置第一個參數,開啓延遲加載,默認情況下的延遲加載是按照層級加載的,而設置了第二個參數之後,代表着按需要加載,只有調用的時候纔會進行加載

第一層: 學生
第二層: 課程成績, 學生證
第三層: 課程

比如,當調用課程成績的時候,如果不設置第二個參數,則 學生證的相關信息也會被加載返回, 設置了第二個參數,則只會返回課程成績

延遲加載的實現原理是通過動態代理實現的,會生成一個動態代理對象,裏面保存着相關的SQL參數,一旦使用這個代理對象的方法,它會進入方法中通過發送SQL和參數就可以把對應的結果從數據庫中查找回來。

動態SQL

mybatiss 提供了豐富的語法實現SQL的動態拼接

  1. if
<!-- test 判斷條件是什麼 , and username .... 是需要拼接的SQL語句-->
<if test="user.username != null and user.username != ''">
        and username = #{user.username}
</if>
  1. choose when otherwise 實現if else 功能
<choose>
    <when test="user.username != null and user.username != ''">
        and username = #{user.username}
    </when>
    <when test="user.username == null or user.username == ''">
        and !(1=1)
    </when>
    <otherwise>
        and !(1=1)
    </otherwise>
<choose>    
  1. trim where set 等標籤, set 標籤完成只更新某些字段,而不是全部的字段的功能
update User
<set>
    <if test="user.username != null and user.username != ''">
        username = #{user.username}
    </if>
    <if test="user.sex != null and user.sex != ''">
        sex = #{user.sex}
    </if>
</set>
where is = #{user.id}
<!-- trim 是過濾功能, 含義是消除掉set標籤中的全部 逗號  -->
<trim prefix = "set" suffixOverridies = ','>
</trim>
  1. foreach 常常用在in 查詢之中
<!--使用動態字符串拼接-->
    <select id="queryUserByUserQueryVo" parameterType="com.dustin.dao.UserQueryVo" resultMap="UserCustomer">
        select * from User
        <!-- where 標籤 裏面書寫if 語句,可以自動將 第一個條件語句中的 = 去掉 -->
        <where>
            <!-- collection 是傳進來的參數名稱, item 是當前變量, open 是語句以什麼開頭,
             close 是以什麼結尾, separator 是遍歷每一個元素的分隔符-->
            <if test="ids != null">
                <foreach collection="ids" item="id" open=" and id in (" close=")" separator=",">
                    #{id}
                </foreach>
            </if>
        </where>
    </select>
  1. bind 這個標籤是定義一個上下文變量,以便於我們在sql 語句中去使用,比如模糊查詢之中 name 是我們起的名字, value 是這個變量的值
<select id="queryUserByUserQueryVo" parameterType="com.dustin.dao.UserQueryVo" resultMap="UserCustomer">
<bind name = "username" value = "'%' + user.username + '' "/>
        select * from User where username like #{username}
</select>

sql 片段 (爲了達到sql語句的複用)

<select id="queryUserByUserQueryVo" parameterType="com.dustin.dao.UserQueryVo" resultMap="UserCustomer">
    select * from User
    <where>
        <!--引用sql 的ID, 如果sql片段不在本地mapper中,需要加上前綴 namespace -->
        <include refid="queryUserByVo"/>
    </where>
</select>
<!-- sql 片段, 方便sql語句的複用 ,一般是基於單表來定義sql片段 -->
<sql id="queryUserByVo">
    <!-- 判斷條件是什麼-->
    <if test="user.username != null and user.username != ''">
        and username = #{user.username}
    </if>
    <!-- 其他語句接着往下寫就行 -->
</sql>

說明: 本文大部分內容都是跟隨者傳播智課的教學視頻學習而來,可以看做是翻譯文章,只是自己吸收之後又書寫一遍,加深自己的知識理解。

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