mybatis基礎系列(三)——動態sql


本文是Mybatis基礎系列的第三篇文章,點擊下面鏈接可以查看前面的文章:

mybatis基礎系列(二)——基礎語法、別名、輸入映射、輸出映射

mybatis基礎系列(一)——mybatis入門

動態sql

MyBatis 的強大特性之一便是它的動態 SQL。擺脫了JDBC中根據不同條件拼接 SQL 語句的痛苦。動態 SQL可以幫我們解決復雜需求。mybatis 動態SQL,通過 if, choose, when, otherwise, trim, where, set, foreach等標簽組合成非常靈活的SQL語句。


根據員工編號或者員工姓名查詢員工信息,輸入的員工編號可能為空。

<select id="queryByEnameOrEempno" parameterType="com.itpsc.request.EmpRequest" resultType="com.itpsc.vo.EmpVo">
    SELECT * FROM t_emp WHERE
    <if test="emp.ename!=null">
      ename=#{emp.ename}
    </if>
    <if test="emp.empno!=null">
      and empno=#{emp.empno}
    </if>
  </select>

執行結果:

編號為空
==>  Preparing: SELECT * FROM t_emp WHERE ename=? 
==> Parameters: itpsc(String)
<==    Columns: empno, ename, job, mgr, hiredate, sal, comm, deptno
<==        Row: 7100, itpsc, developer, 7902, 1980-01-10, null, 1000.00, 20
<==      Total: 1
姓名為空
==>  Preparing: SELECT * FROM t_emp WHERE and empno=? 
==> Parameters: 7100(Integer)

從執行結果可以看出,上面的if語句只能是在員工姓名不能為空的情況下執行,如果員工姓名為空sql語句就出錯了,If+where語句可以解決這個問題。

if+where語句與trim 語句

<select id="queryByEnameOrEempno" parameterType="com.itpsc.request.EmpRequest" resultType="com.itpsc.vo.EmpVo">
    SELECT * FROM t_emp
    <where>
      <if test="emp.ename!=null">
        and ename=#{emp.ename}
      </if>
      <if test="emp.empno!=null">
        and empno=#{emp.empno}
      </if>
    </where>
  </select>

執行結果:

姓名為空
==>  Preparing: SELECT * FROM t_emp WHERE empno=? 
==> Parameters: 7100(Integer)
<==    Columns: empno, ename, job, mgr, hiredate, sal, comm, deptno
<==        Row: 7100, itpsc, developer, 7902, 1980-01-10, null, 1000.00, 20
<==      Total: 1
編號為空
==>  Preparing: SELECT * FROM t_emp WHERE ename=? 
==> Parameters: itpsc(String)
<==    Columns: empno, ename, job, mgr, hiredate, sal, comm, deptno
<==        Row: 7100, itpsc, developer, 7902, 1980-01-10, null, 1000.00, 20
<==      Total: 1

<where>標簽中包含的標簽中有返回值的話,它就插入一個where關鍵字,並且where 標簽會自動將其后第一個條件的and或者是or給忽略掉。

trim語句可以實現<where>標簽類似的功能:

(1)trim標簽可以在包含的內容前加上前綴,也可以在其后加上后綴,對應的屬性是prefix和suffix;

(2)trim標簽可以把包含內容的首部某些內容忽略,也可以把尾部的某些內容忽略,對應的屬性是prefixOverrides和suffixOverrides。

<select id="queryByEnameOrEempno" parameterType="com.itpsc.request.EmpRequest" resultType="com.itpsc.vo.EmpVo">
    SELECT * FROM t_emp
    <trim prefix="where" prefixOverrides="and | or">
      <if test="emp.ename!=null">
        and ename=#{emp.ename}
      </if>
      <if test="emp.empno!=null">
        and empno=#{emp.empno}
      </if>
    </trim>
  </select>

執行結果:

empno為空
==>  Preparing: SELECT * FROM t_emp where ename=? 
==> Parameters: itpsc2(String)
<==    Columns: empno, ename, job, mgr, hiredate, sal, comm, deptno
<==        Row: 7101, itpsc2, developer, 7902, 1980-01-10, 2000.00, 1000.00, 20
<==      Total: 1

ename為空
==>  Preparing: SELECT * FROM t_emp where empno=? 
==> Parameters: 7100(Integer)
<==    Columns: empno, ename, job, mgr, hiredate, sal, comm, deptno
<==        Row: 7100, itpsc1, mannager, 7902, 1980-01-10, null, 1000.00, 20
<==      Total: 1

empno、ename都不為空
==>  Preparing: SELECT * FROM t_emp where ename=? and empno=? 
==> Parameters: itpsc2(String), 7100(Integer)
<==      Total: 0


if+set語句與trim語句

條件判斷用<where>標簽,同理更新操作用<set>標簽。

<select id="updateEnameOrJob" parameterType="com.itpsc.request.EmpRequest">
    UPDATE t_emp
    <set>
      <if test="emp.ename!=null">
        ename=#{emp.ename}
      </if>
      <if test="emp.job!=null">
        job=#{emp.job}
      </if>
    </set>
    WHERE empno=#{emp.empno}
  </select>

運行結果:

job為空
==>  Preparing: UPDATE t_emp SET ename=? WHERE empno=? 
==> Parameters: hello(String), 7100(Integer)
ename 為空
==>  Preparing: UPDATE t_emp SET job=? WHERE empno=? 
==> Parameters: itpsc(String), 7100(Integer)

<set>標簽中包含的標簽中有返回值的話,它就插入一個set關鍵字。job和ename都不為空則sql錯誤,那又如何寫呢,trim標簽可以幫我們能實現。

<select id="updateEnameOrJob" parameterType="com.itpsc.request.EmpRequest">
    UPDATE t_emp
    <trim prefix="set" suffixOverrides=",">
      <if test="emp.ename!=null">
        ename=#{emp.ename},
      </if>
      <if test="emp.job!=null">
        job=#{emp.job},
      </if>
    </trim>
    WHERE empno=#{emp.empno}
  </select>

運行結果:

==>  Preparing: UPDATE t_emp set ename=?, job=? WHERE empno=? 
==> Parameters: itpsc(String), mannager(String), 7100(Integer)

choose(when,otherwise) 語句

上的例子中,job和ename都不為空則是一種條件,job為空且ename不為空是一種條件,ename為空且job不為空是一種條件。實際上,我們要只要滿足任意一個條件,就可以執行。choose(when,otherwise) 語句可以幫我們解決,類似jstl。

<select id="updateEnameOrJob" parameterType="com.itpsc.request.EmpRequest">
    UPDATE t_emp
    <set>
      <choose>
        <when test="emp.ename!=null and emp.job!=null">
          ename=#{emp.ename},job=#{emp.job}
        </when>
        <otherwise>
          <if test="emp.ename!=null">
            ename=#{emp.ename}
          </if>
          <if test="emp.job!=null">
            job=#{emp.job}
          </if>
        </otherwise>
      </choose>
    </set>
    WHERE empno=#{emp.empno}
  </select>

執行結果:

ename為空且job不為空
==>  Preparing: UPDATE t_emp SET job=? WHERE empno=? 
==> Parameters: mannager(String), 7100(Integer)

job為空且ename不為空
==>  Preparing: UPDATE t_emp SET ename=? WHERE empno=? 
==> Parameters: itpsc2(String), 7100(Integer)

job和ename都不為空
==>  Preparing: UPDATE t_emp SET ename=?,job=? WHERE empno=? 
==> Parameters: itpsc2(String), mannager(String), 7100(Integer)

foreach 語句

需求:根據員工編號列表查詢員工信息。7369,7499,7521。

Sql的寫法是:select * from t_emp where 1=1 and empno=7369 or empno=7499 or empno=7521

mybatis的foreach語句可以幫我們實現類似功能。

<select id="queryByIds" 
parameterType="com.itpsc.request.IdRequest" resultType="com.itpsc.vo.EmpVo">
    SELECT * FROM t_emp
    <where>
      <foreach collection="ids" item="id" open="and (" close=")" separator="or">
        empno=#{id}
      </foreach>
    </where>
  </select>

collection:指定輸入對象中的集合屬性

item:每次遍歷生成的對象

open:開始遍歷時的拼接字符串

close:結束時拼接的字符串

separator:遍歷對象之間需要拼接的字符串

運行結果:

==>  Preparing: SELECT * FROM t_emp WHERE ( empno=? or empno=? or empno=? ) 
==> Parameters: 7369(Integer), 7499(Integer), 7521(Integer)
<==    Columns: empno, ename, job, mgr, hiredate, sal, comm, deptno
<==        Row: 7369, SMITH, CLERK, 7902, 1980-12-17, 800.00, null, 20
<==        Row: 7499, ALLEN, SALESMAN, 7698, 1981-02-20, 1600.00, 300.00, 30
<==        Row: 7521, WARD, SALESMAN, 7698, 1981-02-22, 1250.00, 500.00, 30
<==      Total: 3

sql片段

將上面動態sql代碼塊抽取出來,組成一個sql片段,其它的statement中就可以引用該sql片段。提供代碼復用性,方便團隊成員之間進行開發。


<select id="queryCount2" parameterType="com.itpsc.request.EmpRequest" resultType="int">
    SELECT count(*) FROM t_emp
    <where>
      <if test="emp!=null">
        <if test="emp.deptno!=null">
          and emp.deptno=#{emp.deptno}
        </if>
        <if test="emp.ename!=null">
          and emp.ename=#{emp.ename}
        </if>
        <if test="emp.job!=null">
          and emp.job=#{emp.job}
        </if>
      </if>
    </where>
  </select>

上面where語句中代碼,我們可以通過<sql>標簽封裝成一個sql片段,然后在其它statement中通過<include>引用。

<sql id="querySql">
    <if test="emp!=null">
      <if test="emp.deptno!=null">
        and emp.deptno=#{emp.deptno}
      </if>
      <if test="emp.ename!=null">
        and emp.ename=#{emp.ename}
      </if>
      <if test="emp.job!=null">
        and emp.job=#{emp.job}
      </if>
    </if>
  </sql>
  
  <select id="queryCount2" parameterType="com.itpsc.request.EmpRequest" resultType="int">
    SELECT count(*) FROM t_emp
    <where>
      <include refid="querySql"></include>
    </where>
  </select>


本文到此,下篇 mybatis基礎系列(四)——關聯查詢、延遲加載、一級緩存與二級緩存。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM