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 問題:
- 你執行了一個單獨的 SQL 語句來獲取結果列表(就是“+1”)。
- 對返回的每條記錄,你執行了一個查詢語句來爲每個加載細節(就是“N”)。
這個問題會導致成百上千的 SQL 語句被執行。這通常不是期望的。
Mybatis 的解決方案: 延遲加載 能大大提高數據庫的性能,因爲單標查詢的速度要比多表查詢快
兩個參數:
設置 lazzyLoadingEnabled = true 開啓延遲加載功能
設置 aggeressiveLazzyLoading = false 將代表着 延遲加載下的 按需加載,即調用時纔會進行加載
如果只設置第一個參數,開啓延遲加載,默認情況下的延遲加載是按照層級加載的,而設置了第二個參數之後,代表着按需要加載,只有調用的時候纔會進行加載
第一層: 學生
第二層: 課程成績, 學生證
第三層: 課程
比如,當調用課程成績的時候,如果不設置第二個參數,則 學生證的相關信息也會被加載返回, 設置了第二個參數,則只會返回課程成績
延遲加載的實現原理是通過動態代理實現的,會生成一個動態代理對象,裏面保存着相關的SQL參數,一旦使用這個代理對象的方法,它會進入方法中通過發送SQL和參數就可以把對應的結果從數據庫中查找回來。
動態SQL
mybatiss 提供了豐富的語法實現SQL的動態拼接
- if
<!-- test 判斷條件是什麼 , and username .... 是需要拼接的SQL語句-->
<if test="user.username != null and user.username != ''">
and username = #{user.username}
</if>
- 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>
- 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>
- 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>
- 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>
說明: 本文大部分內容都是跟隨者傳播智課的教學視頻學習而來,可以看做是翻譯文章,只是自己吸收之後又書寫一遍,加深自己的知識理解。