Java-Mybatis動態SQL整理

Tttori發表於2021-08-17

XML對映器



SQL對映檔案的幾個頂級元素:

  • cache - 該名稱空間的快取配置

  • cache-ref - 引用其他名稱空間的快取配置

  • resultMap - 描述如何從資料庫結果集中載入物件

  • sql - 可被其他語句引用的可重用語句塊

  • insert - 增

  • update - 改

  • delete - 刪

  • select - 查


select屬性

屬性 描述
id 識別符號,與Mapper中對應方法的方法名一致
parameterType 傳入這條語句的引數的類全限定名或別名
resultType 返回結果的類全限定名或別名,如果返回的是集合,應設定為集合包含的型別而不是集合本身的型別。resultType和resultMap之間只能使用一個
resultMap 對外部resultMap的命名引用,結果對映是Mybatis的最強大的特性

sql

sql元素可以用來定義可重用的SQL程式碼片段,以便在其他語句中使用。引數可以靜態地(載入的時候)確定下來並且可以在不同的include元素中定義不同的引數值

<sql id="userColumns">
	${alias}.id,${alias}.usernname,${alias}.password
</sql>

常用在include元素的refid屬性或內部語句中使用屬性值

<sql id="sometable">
	${preifx}Table
</sql>

<sql id="someinclude">
	FROM
    <include refid="${include_target}"/>
</sql>

<select id="select" resultType="Map">
	SELECT
    	field1,field2,field3
    <include refid="someinclude">
    	<property name="prefix" value="Some"/>
        <property name="include_target" value="sometable"/>
    </include>
</select>

ResultMap

一對一查詢:

<!-- 屬性名不一致或進行關聯查詢時,可用resultMap標籤 
     以查詢訂單為例,從查詢訂單角度出發為一對一,因為一個訂單隻會是一個人下的 -->
1)改造實體類:
	<!-- 在訂單類中新增User屬性,即一個引用型別 -->

2)編寫resultMap:
<resultMap type="order" id="orderUserResultMap">
	<id property="id" column="id"/>
    <result property="userId" column="user_id"/>
    ...
    <result property="note" column="note"/>
    <association property="user" javaType="user">
    	<id property="id" column="id"/>
        <result property="username" column="username"/>
        ...
    </association>
</resultMap>

3)呼叫例項:
<!-- 一對一關聯,查詢訂單,訂單內部包含使用者屬性 -->
<select id="queryOrderUserResultMap" resultMap="orderUserResultMap">
    SELECT
    o.id,
    o.user_id,
    o.number,
    o.createtime,
    o.note,
    u.username,
    u.address
    FROM
    `order` o
    LEFT JOIN `user` u ON o.user_id = u.id
</select>

一對多查詢:

<!-- 查詢所有使用者資訊及相關訂單 -->
<!-- 對於使用者而言,一個使用者可能對應多個不同的訂單,即一對多 -->
1)改造實體類:
	新增訂單集合屬性,如:List< Order > orders

2)編寫resultMap:
<resultMap type="user" id="userOrderResultMap">
    <id property="id" column="id" />
    <result property="username" column="username" />
    <result property="birthday" column="birthday" />
    <result property="sex" column="sex" />
    <result property="address" column="address" />

    <!-- 配置一對多的關係
        property:填寫pojo類中List集合類類屬性的名稱
        javaType:填寫集合型別的名稱 
    -->
    <collection property="orders" javaType="list" ofType="order">
        <!-- 配置主鍵,是關聯Order的唯一標識 -->
        <id property="id" column="oid" />
        <result property="number" column="number" />
        <result property="createtime" column="createtime" />
        <result property="note" column="note" />
    </collection>
</resultMap>

3)呼叫例項:
<!-- 一對多關聯,查詢訂單同時查詢該使用者下的訂單 -->
<select id="queryUserOrder" resultMap="userOrderResultMap">
    SELECT
    u.id,
    u.username,
    u.birthday,
    u.sex,
    u.address,
    o.id oid,
    o.number,
    o.createtime,
    o.note
    FROM
    `user` u
    LEFT JOIN `order` o ON u.id = o.user_id
</select>


動態SQL



簡介

主要介紹Mybatis提供的幾種用於實現動態SQL的標籤的基本使用方式:

  • if
  • choose、when、otherwise
  • trim、where、set
  • foreach

if

if 語句提供了可選的查詢文字功能

若 if 中條件成立,則執行 if 標籤中的語句,拼接至SQL語句中

若 if 中條件不成立,則忽略,舉個例子:

<select id="findActiveBlogWithTitleLike" resultType="Blog">
    SELECT * FROM BLOG
    WHERE state = 'ACTIVE'
    <if test="title != null">
        AND title like #{title}
    </if>
    <if test="author != null and author.name != null">
        AND author_name like #{author.name}
    </if>
</select>

choose、when、otherwise

Mybatis提供的choose元素,類似Java的switch語句,可從多個條件中選擇一個使用

舉個例子:傳入了"title"就按"title"查詢,傳入了"author"就按"author"查詢的情形。

若兩者都沒有傳入,就返回標記為featured=1的BLOG(若多個條件滿足則遵循就近原則)

<select id="findActiveBlogLike" resultType="Blog">
    SELECT * FROM BLOG
    WHERE state = 'ACTIVE'
    <choose>
        <when test="title !=null">
            AND title like #{title}
        </when>
        <when test="author != null and author.name != null">
            AND author_name like #{author.name}
        </when>
        <otherwise>
            AND featured = 1
        </otherwise>
    </choose>
</select>

trim、where、set

where

如何將上例中的"state='ACTIVE'"條件設定為動態條件,即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>
</select>

按上面所寫,如果沒有匹配的條件,SQL會變成:

SELECT * FROM BLOG
WHERE

導致查詢失敗。如果匹配的只是第二/三個條件,SQL會變成:

SELECT * FROM BLOG
WHERE
AND title like 'title'

從上例可看出 WHERE 語句後的第一個條件想要實現動態SQL不能簡單使用條件元素來解決,對此可以使用Mybatis提供的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>

where元素只會在子元素返回任何內容的情況下才插入"WHERE"子句。並且若子句的開頭為"AND"或"OR",where元素也會將它們去除


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

如果選擇的元素與你期望的不大一樣,可以通過自定義trim元素來制定元素的功能,比如:

where標籤:

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

set標籤:

<trim prefix="set" suffixOverrides=",">
    ...
</trim>

prefix:字首

prefixOverrides:字首覆蓋,忽略通過管道符分隔的文字序列

suffixOverrides:字尾覆蓋,覆蓋了字尾值的設定


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>

可以將任何可迭代物件(List, Set)、Map或陣列物件作為集合引數傳遞給foreach。當使用可迭代物件或者陣列時,index是當前迭代的序號,item的值是本次迭代獲取到的元素。使用Map物件時,index是key,item是value




相關文章