天天看點

Java單體應用 - 常用架構 - 08.MyBatis - MyBatis 動态 SQLMyBatis 動态 SQL

原文位址: http://www.work100.net/training/monolithic-frameworks-mybatis-sql.html 更多教程: 光束雲 - 免費課程

MyBatis 動态 SQL

請參照如上

章節導航

進行閱讀

1.概述

動态 SQL,主要用于解決查詢條件不确定的情況:在程式運作期間,根據使用者送出的查詢條件進行查詢。

送出的查詢條件不同,執行的 SQL 語句不同。若将每種可能的情況均逐一列出,對所有條件進行排列組合,将會出現大量的 SQL 語句。

此時,可使用動态 SQL 來解決這樣的問題。

動态 SQL,即通過 MyBatis 提供的各種标簽對條件作出判斷以實作動态拼接 SQL 語句。

這裡的條件判斷使用的表達式為 OGNL 表達式。常用的動态 SQL 标簽有

<if>

<where>

<choose>

<foreach>

等。

2.注意事項

在 mapper 的動态 SQL 中若出現大于号(

>

)、小于号(

<

)、大于等于号(

>=

),小于等于号(

<=

)等符号,最好将其轉換為實體符号。

否則,XML 可能會出現解析出錯問題。

特别是對于小于号(

<

),在 XML 中是絕對不能出現的。否則,一定出錯。

原符号 替換符号

<

<

<=

<=

>

>

>=

>=

&

&

'

&apos;

"

"

3.if标簽

對于該标簽的執行,當

test

的值為

true

時,會将其包含的 SQL 片斷拼接到其所在的 SQL 語句中。

本例實作的功能是:查詢出滿足使用者送出查詢條件的所有學生。使用者送出的查詢條件可以包含一個姓名的模糊查詢,同時還可以包含一個年齡的下限。當然,使用者在送出表單時可能兩個條件均做出了設定,也可能兩個條件均不做設定,也可以隻做其中一項設定。

這引發的問題是,查詢條件不确定,查詢條件依賴于使用者送出的内容。此時,就可使用動态 SQL 語句,根據使用者送出内容對将要執行的 SQL 進行拼接。

定義映射檔案

為了解決兩個條件均未做設定的情況,在

where

後添加了一個“

1=1

”的條件。

這樣就不至于兩個條件均未設定而出現隻剩下一個

where

,而沒有任何可拼接的條件的不完整 SQL 語句。

<?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="net.work100.training.stage2.mybatis.dao.DynamicStudentDao">
    <!-- if -->
    <select id="selectByIf" resultType="net.work100.training.stage2.mybatis.entity.Student">
        SELECT
            id,
            name,
            age,
            score
        FROM
            student
        WHERE 1 = 1
        <if test="name != null and name != ''">
            AND name LIKE concat('%', #{name}, '%')
        </if>
        <if test="age != null and age > 0">
            AND age > #{age}
        </if>
    </select>
</mapper>           

4.where标簽

<if/>

标簽的中存在一個比較麻煩的地方:需要在

where

後手工添加

1=1

的子句。

因為,若

where

後的所有

<if/>

條件均為

false

,而

where

後若又沒有

1=1

子句,則 SQL 中就會隻剩下一個空的

where

,SQL 出錯。

是以,在

where

後,需要添加永為真子句

1=1

,以防止這種情況的發生。但當資料量很大時,會嚴重影響查詢效率。

<!-- where-->
<select id="selectByWhere" resultType="net.work100.training.stage2.mybatis.entity.Student">
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
    <where>
        <if test="name != null and name != ''">
            AND name LIKE concat('%', #{name}, '%')
        </if>
        <if test="age != null and age > 0">
            AND age > #{age}
        </if>
    </where>
</select>           

5.choose标簽

該标簽中隻可以包含

<when/> <otherwise/>

,可以包含多個

<when/>

與一個

<otherwise/>

它們聯合使用,完成 Java 中的開關語句

switch..case

功能。

本例要完成的需求是,若姓名不空,則按照姓名查詢;若姓名為空,則按照年齡查詢;若沒有查詢條件,則沒有查詢結果。

<!-- choose -->
<select id="selectByChoose" resultType="net.work100.training.stage2.mybatis.entity.Student">
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
    <where>
        <choose>
            <when test="name != null and name != ''">
                AND name LIKE concat('%', #{name}, '%')
            </when>
            <when test="age != null and age > 0">
                AND age > #{age}
            </when>
            <otherwise>
                AND 1 != 1
            </otherwise>
        </choose>
    </where>
</select>           

6.foreach标簽-周遊數組

<foreach/>

标簽用于實作對于數組與集合的周遊。對其使用,需要注意:

  • collection

    表示要周遊的集合類型,這裡是數組,即

    array

  • open

    close

    separator

    為對周遊内容的 SQL 拼接。

本例實作的需求是,查詢出 id 為 2 與 4 的學生資訊。

動态 SQL 的判斷中使用的都是 OGNL 表達式。

OGNL 表達式中的數組使用

array

表示,數組長度使用

array.length

表示。

<!-- foreach -->
<select id="selectByForeach" resultType="net.work100.training.stage2.mybatis.entity.Student">
    <!-- select * from student where id in (2, 4) -->
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
    <if test="array != null and array.length > 0">
        WHERE id IN
        <foreach collection="array" open="(" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </if>
</select>           

7.foreach标簽-周遊集合

周遊集合的方式與周遊數組的方式相同,隻不過是将

array

替換成了

list

周遊泛型為基本類型的 List

定義 DAO 接口

/**
 * 使用 foreach 标簽以 list 基本類型的形式查詢
 * @param ids
 * @return
 */
public List<Student> selectByForeachWithListBase(List<Long> ids);           

<!-- foreach -->
<select id="selectByForeachWithListBase" resultType="net.work100.training.stage2.mybatis.entity.Student">
    <!-- select * from student where id in (2, 4) -->
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
    <if test="list != null and list.size > 0">
        WHERE id IN
        <foreach collection="list" open="(" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </if>
</select>           

周遊泛型為自定義類型的 List

/**
 * 使用 foreach 标簽以 list 自定義類型的形式查詢
 * @param students
 * @return
 */
public List<Student> selectByForeachWithListCustom(List<Student> students);           

<!-- foreach -->
<select id="selectByForeachWithListCustom" resultType="net.work100.training.stage2.mybatis.entity.Student">
    <!-- select * from student where id in (2, 4) -->
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
    <if test="list != null and list.size > 0">
        WHERE id IN
        <foreach collection="list" open="(" close=")" item="student" separator=",">
            #{student.id}
        </foreach>
    </if>
</select>           

8.sql标簽

<sql/>

标簽用于定義 SQL 片斷,以便其它 SQL 标簽複用。

而其它标簽使用該 SQL 片斷, 需要使用

<include/>

子标簽。

<sql/>

标簽可以定義 SQL 語句中的任何部分,是以

<include/>

子标簽可以放在動态 SQL 的任何位置。

修改映射檔案

<sql id="select">
    SELECT
        id,
        name,
        age,
        score
    FROM
      student
</sql>           
<!-- foreach -->
<select id="selectByForeachWithListCustom" resultType="net.work100.training.stage2.mybatis.entity.Student">
    <!-- select * from student where id in (2, 4) -->
    <include refid="select" />

    <if test="list != null and list.size > 0">
        WHERE id IN
        <foreach collection="list" open="(" close=")" item="student" separator=",">
            #{student.id}
        </foreach>
    </if>
</select>           

上一篇:

MyBatis 單表 CRUD 操作
如果對課程内容感興趣,可以掃碼關注我們的

公衆号

QQ群

,及時關注我們的課程更新
Java單體應用 - 常用架構 - 08.MyBatis - MyBatis 動态 SQLMyBatis 動态 SQL
Java單體應用 - 常用架構 - 08.MyBatis - MyBatis 動态 SQLMyBatis 動态 SQL