MyBatis-動態SQL的if、choose、when、otherwise、trim、where、set、foreach使用(各種標簽詳解), 以及實體間關系配置


 

比較全的文檔:https://www.cnblogs.com/zhizhao/p/7808880.html 或 https://blog.csdn.net/zhll3377/article/details/8203440

 

四:常用的動態語句標簽:通過動態sql標簽可以進行條件判斷,條件遍歷等操作從而滿足結果的需要

  0. </if>

<select id="dynamicIfTest" parameterType="Blog" resultType="Blog"> select * from t_blog where 1 = 1
    <if test="title != null"> and title = #{title} </if>
    <if test="content != null"> and content = #{content} </if>
    <if test="owner != null"> and owner = #{owner} </if>
</select>

 

 

<!-- 查詢學生list,like姓名    concat: ‘字符串拼接’-->   
<select id=" getStudentListLikeName " parameterType="StudentEntity" resultMap="studentResultMap"> SELECT * from STUDENT_TBL ST <if test="studentName!=null and studentName!='' "> WHERE ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName}),'%') </if>   
</select>   

 

<select id="getEmpByIf" resultType="Emp" parameterType="Emp"> select * from emp where 1 = 1
    <if test="job != null and job != ''"> and job = #{job} </if>
    <if test="deptno != null "> and deptno = #{deptno} </if>
</select>

 

  1. <where> : 使用其可以代替sql語句中的where關鍵字,一般防止在條件查詢的最外層

  2.<set>:常用於<update>更新語句中,替代 sql中的“set”關鍵字,特別是在聯合<if>進行判斷是,可以有效方式當某個參數為空或者不合法是錯誤的更新到數據庫中

  

 <update id="updateByPrimaryKeySelective" parameterType="pojo.Orderitem" > update orderitem <set >
      <if test="productId != null" > product_id = #{productId,jdbcType=VARCHAR}, </if>
      <if test="count != null" > count = #{count,jdbcType=INTEGER}, </if>
    </set> where orderitem_id = #{orderitemId,jdbcType=VARCHAR} </update>

  3. <choose><when></when><otherwise></otherwise></choose> 標簽組:也是一個用於條件判斷的標簽組,和<if>的不同之處在於條件從<choose>進入,去匹配<when>中的添加,一旦匹配馬上結束;若到找不到匹配項,將執行<other>中的語句;可以理解為<if>是 && 關系 <choose>是 || 關系 

  

<!-- 查詢學生list,like姓名、或=性別、或=生日、或=班級,使用choose -->     
<select id="getStudentListChooseEntity" parameterType="StudentEntity" resultMap="studentResultMap"> SELECT * from STUDENT_TBL ST <where>     
        <choose>     
            <when test="studentName!=null and studentName!='' "> ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName}),'%') </when>     
            <when test="studentSex!= null and studentSex!= '' "> AND ST.STUDENT_SEX = #{studentSex} </when>     
            <when test="studentBirthday!=null"> AND ST.STUDENT_BIRTHDAY = #{studentBirthday} </when>     
            <when test="classEntity!=null and classEntity.classID !=null and classEntity.classID!='' "> AND ST.CLASS_ID = #{classEntity.classID} </when>     
            <otherwise>     
                      
            </otherwise>     
        </choose>     
    </where>     
</select>   

3.1. <choose>:   

有時候我們並不想應用所有的條件,而只是想從多個選項中選擇一個。MyBatis提供了choose 元素,按順序判斷when中的條件出否成立,如果有一個成立,則choose結束。當choose中所有when的條件都不滿則時,則執行 otherwise中的sql。類似於Java 的switch 語句,choose為switch,when為case,otherwise則為default。  if是與(and)的關系,而choose是或(or)的關系。 

 

5. <set>  

當在update語句中使用if標簽時,如果前面的if沒有執行,則或導致逗號多余錯誤。使用set標簽可以將動態的配置SET 關鍵字,和剔除追加到條件末尾的任何不相關的逗號。
沒有使用if標簽時,如果有一個參數為null,都會導致錯誤,如下示例:

<!-- 更新學生信息 -->   
<update id="updateStudent" parameterType="StudentEntity"> UPDATE STUDENT_TBL SET STUDENT_TBL.STUDENT_NAME = #{studentName}, STUDENT_TBL.STUDENT_SEX = #{studentSex}, STUDENT_TBL.STUDENT_BIRTHDAY = #{studentBirthday}, STUDENT_TBL.CLASS_ID = #{classEntity.classID} WHERE STUDENT_TBL.STUDENT_ID = #{studentID}; </update>   

 

6.<trim>標簽:

update user <trim prefix="set" suffixOverrides="," suffix=" where id = #{id} "> <if test="name != null and name.length()>0"> name=#{name} , </if> <if test="gender != null and gender.length()>0"> gender=#{gender} , </if> </trim>

 

 

1>. <trim prefix="" suffix="" suffixOverrides="" prefixOverrides=""></trim>
prefix:在trim標簽內sql語句加上前綴。
suffix:在trim標簽內sql語句加上后綴。
suffixOverrides:指定去除多余的后綴內容,如:suffixOverrides=",",去除trim標簽內sql語句多余的后綴","。
prefixOverrides:指定去除多余的前綴內容

下面是一個往購物車表中插入數據的mybatis語句

<insert id="insert" parameterType="com.tortuousroad.groupon.cart.entity.Cart"> insert into cart <trim prefix="(" suffix=")" suffixOverrides=","> (把 尾部的,替換成 ")")
            <if test="id != null"> id, </if>
            <if test="userId != null"> user_id, </if>
            <if test="dealId != null"> deal_id, </if>
            <if test="dealSkuId != null"> deal_sku_id, </if>
            <if test="count != null"> count, </if>
            <if test="createTime != null"> create_time, </if>
            <if test="updateTime != null"> update_time, </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null"> #{id,jdbcType=BIGINT}, </if>
            <if test="userId != null"> #{userId,jdbcType=BIGINT}, </if>
            <if test="dealId != null"> #{dealId,jdbcType=BIGINT}, </if>
            <if test="dealSkuId != null"> #{dealSkuId,jdbcType=BIGINT}, </if>
            <if test="count != null"> #{count,jdbcType=INTEGER}, </if>
            <if test="createTime != null"> #{createTime,jdbcType=TIMESTAMP}, </if>
            <if test="updateTime != null"> #{updateTime,jdbcType=TIMESTAMP}, </if>
        </trim>
    </insert>

假設沒有指定 suffixOverrides="," ,  

執行的sql語句也許是這樣的:insert into cart (id,user_id,deal_id,) values(1,2,1,);顯然是錯誤的
指定之后語句就會變成            insert into cart (id,user_id,deal_id) values(1,2,1);這樣就將“,”去掉了。
前綴也是一個道理這里就不說了。

來自: https://blog.csdn.net/qq_33054511/article/details/70490046

 

 

 

o(^▽^)o可以看到成功匹配掉了開頭的$和末尾的*

String[] deptnos = {"10", "20", "30"};

List<Emp> empList = sqlSession.getMapper(EmpMapper.class).getEmpByArray(deptnos);

 2>.

   trim是更靈活的去處多余關鍵字的標簽,他可以實踐where和set的效果。 where例子的等效trim語句:

 <!-- 查詢學生list,like姓名,=性別   傳入參數 map 或 實體 即可-->   
<select id="getStudentListWhere" parameterType="StudentEntity" resultMap="studentResultMap"> SELECT * from STUDENT_TBL ST <trim prefix="WHERE" prefixOverrides="AND|OR">   (頭部的and或or 都替換成"where")
        <if test="studentName!=null and studentName!='' "> ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName}),'%') </if>   
        <if test="studentSex!= null and studentSex!= '' "> AND ST.STUDENT_SEX = #{studentSex} </if>   
        <if test="position!=null">     AND ST.position like #{position}       </if>   </trim>   
</select>   

【解釋】

a.我們使用<trim>替代<where>標簽。

b.屬性“prefix”表示:加入前綴where

c.屬性“prefixOverrides”表示:自動覆蓋第一個“and”或者“or”

d.后綴的用法類似;

set例子的等效trim語句(<trim>是一個非常強大的標簽,因此,我們也可以通過<trim>來實現<set>的功能,如下:【這種寫法的運行效果與<set>等價】):

<!-- 更新學生信息 -->   
<update id="updateStudent" parameterType="StudentEntity"> UPDATE STUDENT_TBL <trim prefix="SET" suffixOverrides=",">   
        <if test="studentName!=null and studentName!='' "> STUDENT_TBL.STUDENT_NAME = #{studentName}, </if>   
        <if test="studentSex!=null and studentSex!='' "> STUDENT_TBL.STUDENT_SEX = #{studentSex}, </if>   
        <if test="studentBirthday!=null "> STUDENT_TBL.STUDENT_BIRTHDAY = #{studentBirthday}, </if>   
        <if test="classEntity!=null and classEntity.classID!=null and classEntity.classID!='' "> STUDENT_TBL.CLASS_ID = #{classEntity.classID} </if>   
    </trim> WHERE STUDENT_TBL.STUDENT_ID = #{studentID}; </update>   

 

7.<foreach>標簽:該標簽的作用是遍歷集合類型的條件 

  屬性:collection=“array” / collection = “list”  ----->是數組類型,還是集合類型

              item=“ productId ”------> 參數名

      open="(" separator="," close=")"  ------>開始符號,分隔符號,結束符號 

      index=“ ” ---->結束下標位置,不配置該參數時,默認為全部遍歷 

 <delete id="deleteByPriKeys" parameterType="java.lang.String">
       delete from product where product_Id in
       <foreach collection="list" item="productId" open="(" separator="," close=")">
            #{productId,jdbcType = VARCHAR}
       </foreach>
  </delete> 

 

3.4.  參數為Array實例的寫法:

<select id="getStudentListByClassIDs" resultMap="studentResultMap"> SELECT * FROM STUDENT_TBL ST WHERE ST.CLASS_ID IN <foreach collection="array" item="ids"  open="(" separator="," close=")"> #{ids} </foreach>   
</select>   

接口的方法聲明:

public List<StudentEntity> getStudentListByClassIDs(String[] ids);
public List<StudentEntity> getStudentListByClassIDs(String[] ids);測試代碼,查詢學生中,在20000002、20000003這兩個班級的學生:

 3.5. Map類型的參數

<select id="dynamicForeach3Test" resultType="com.mybatis.entity.User">
    select * from t_user where username like '%${username}%' and id in
    <foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>
public List<User> dynamicForeach3Test(Map<String, Object> params); 

 

五、(https://blog.csdn.net/qq_29233973/article/details/51433924 + https://blog.csdn.net/zenson_g/article/details/10137665)

1. 引用:通過<include refid="" />標簽引用,refid="" 中的值指向需要引用的<sql>中的id=“”屬性

<!--定義sql片段-->
<sql id="orderAndItem">
      o.order_id,o.cid,o.address,o.create_date,o.orderitem_id,i.orderitem_id,i.product_id,i.count
  </sql>
 
 <select id="findOrderAndItemsByOid" parameterType="java.lang.String" resultMap="BaseResultMap">
      select
<!--引用sql片段-->
      <include refid="orderAndItem" />
      from ordertable o
      join orderitem i on o.orderitem_id = i.orderitem_id
      where o.order_id = #{orderId}
  </select>

2. 映射管理器resultMap:映射管理器,是Mybatis中最強大的工具,使用其可以進行實體類之間的關系,並管理結果和實體類間的映射關系:

1)一對一關系<assocation property = " " javaType=" ">   property = “ ” 被維護實體在宿主實體中的屬性名,javaType = " " 被維護實體的類型

package pojo;
 
public class Orderitem {
  
    private String orderitemId;
 
    private String productId;
 
    private Integer count;
    
    private Product product;   

從上方代碼段可以看出:Product 對象在 Orderitem 實體中以 product 屬性存在 

Orderitemmapper.xml

 <resultMap id="BaseResultMap" type="pojo.Orderitem" >
    <id column="orderitem_id" property="orderitemId" jdbcType="VARCHAR" />
    <result column="product_id" property="productId" jdbcType="VARCHAR" />
    <result column="count" property="count" jdbcType="INTEGER" />
    <!-- 通過association 維護 一對一關系 -->
    <association property="product" javaType="pojo.Product">
        <id column="product_id" property="productId"/>
        <result column="product_factroy" property="productFactroy"/>
        <result column="product_store" property="productStore"/>
        <result column="product_descript" property="productDescript"/>
    </association>
  </resultMap>

通過xml的配置可以看出,在resultMap映射管理器中,通過<association> 進行了維護,也就是在查詢Orderitem對象時,可以把關聯的Product對象的信息也查詢出來

2)一對多關系的維護<collection property=" " ofType=" "> property = “ ” 被維護實體在宿主實體中的屬性名 ,ofType=“ ”是被維護方在宿主類中集合泛型限定類型

【由於在一對多關系中,多的一放是以List形式存在,因此ofType的值取用Lsit<?> 的泛型對象類型】

public class OrderTable {
 
    private String orderId;
 
    private String cid;
 
    private String address;
 
    private Date createDate;
 
    private String orderitemId;
   
    private List<Orderitem> orderitemList ;
}

OrderTableMapper.xml:

 <resultMap id="BaseResultMap" type="pojo.OrderTable" >
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Fri May 06 15:49:42 CST 2016.
    -->
    <id column="order_id" property="orderId" jdbcType="VARCHAR" />
    <result column="cid" property="cid" jdbcType="VARCHAR" />
    <result column="address" property="address" jdbcType="VARCHAR" />
    <result column="create_date" property="createDate" jdbcType="TIMESTAMP" />
    <result column="orderitem_id" property="orderitemId" jdbcType="VARCHAR" />
         <!--維護一對多的關系  -->
        <collection property="orderitemList" ofType="pojo.Orderitem">
            <id column="orderitem_id" property="orderitemId"/>
            <result column="product_id" property="productId"/>
            <result column="count" property="count"/>
        </collection> 
  </resultMap>

3)在resultMap 中需要注意兩點:

3.1)關聯關系的維護可以根據實體類之間的實際情況進行嵌套維護

<resultMap id="BaseResultMap" type="pojo.OrderTable" >
    <id column="order_id" property="orderId" jdbcType="VARCHAR" />
    <result column="cid" property="cid" jdbcType="VARCHAR" />
    <result column="address" property="address" jdbcType="VARCHAR" />
    <result column="create_date" property="createDate" jdbcType="TIMESTAMP" />
    <result column="orderitem_id" property="orderitemId" jdbcType="VARCHAR" />
         <!--維護一對多的關系  -->
        <collection property="orderitemList" ofType="pojo.Orderitem">
            <id column="orderitem_id" property="orderitemId"/>
            <result column="product_id" property="productId"/>
            <result column="count" property="count"/>
<span style="white-space:pre">        </span><!--嵌套一對一關系-->
            <association property="customer" javaType="pojo.Customer">
                <id column="cid" property="cid"/>
                <result column="cname" property="cname"/>
            </association>
        </collection> 
  </resultMap>

實例:

我們又一次聯合了博客表和文章表,而且關注於保證特性,結果列標簽的簡單映射。現在用文章映射集合映射博客,可以簡單寫為:

<resultMap id="blogResult" type="Blog">
   <id property="id" column="blog_id" />
   <result property="title" column="blog_title"/>
   <collection property="posts" ofType="Post">
     <id property="id" column="post_id"/>
     <result property="subject" column="post_subject"/>
     <result property="body" column="post_body"/>
   </collection>
 </resultMap>
同樣,要記得 id 元素的重要性,如果你不記得了,請閱讀上面的關聯部分。

同樣, 如果你引用更長的形式允許你的結果映射的更多重用, 你可以使用下面這個替代的映射:

<resultMap id="blogResult" type="Blog">
   <id property="id" column="blog_id" />
   <result property="title" column="blog_title"/>
   <collection property="posts" ofType="Post" resultMap="blogPostResult" columnPrefix="post_"/>
 </resultMap>
 <resultMap id="blogPostResult" type="Post">
   <id property="id" column="id"/>
   <result property="subject" column="subject"/>
   <result property="body" column="body"/>
 </resultMap>

注意 這個對你所映射的內容沒有深度,廣度或關聯和集合相聯合的限制。當映射它們時你應該在大腦中保留它們的表現。你的應用在找到最佳方法前要一直進行的單元測試和性能測試。好在 myBatis 讓你后來可以改變想法,而不對你的代碼造成很小(或任何)影響。

高級關聯和集合映射是一個深度的主題。文檔只能給你介紹到這了。加上一點聯系,你會很快清楚它們的用法。

 

3.2)關於出現重復列名的處理:在實際操作過程中,查詢到的結果可能會出現相同的列名,這樣會對映射到實體屬性帶來影響甚至出現報錯,那么對待這個問題可以通過對列取別名的方式處理:

要記住類型別名是你的伙伴。使用它們你可以不用輸入類的全路徑。比如:

<!-- In mybatis-config.xml file -->
<typeAlias type="com.someapp.model.User" alias="User"/>
<!-- In SQL Mapping XML file -->
<select id="selectUsers" parameterType="int" resultType="User"> select id, username, hashedPassword from some_table where id = #{id} </select>

這些情況下,MyBatis 會在幕后自動創建一個 ResultMap,基於屬性名來映射列到 JavaBean 的屬性上。如果列名沒有精確匹配,你可以在列名上使用 select 字句的別名(一個基本的 SQL 特性)來匹配標簽。比如:

<select id="selectUsers" parameterType="int" resultType="User"> select user_id as "id", user_name as "userName", hashed_password as "hashedPassword" from some_table where id = #{id} </select>

ResultMap 最優秀的地方你已經了解了很多了,但是你還沒有真正的看到一個。這些簡單的示例不需要比你看到的更多東西。只是出於示例的原因, 讓我們來看看最后一個示例中外部的 resultMap 是什么樣子的,這也是解決列名不匹配的另外一種方式。

<resultMap id="userResultMap" type="User">   
<id property="id" column="user_id" />
<result property="username" column="username"/>
<result property="password" column="password"/>
</resultMap>
引用它的語句使用 resultMap 屬性就行了(注意我們去掉了 resultType 屬性)。比如:
<select id="selectUsers" parameterType="int" resultMap="userResultMap">  
    select user_id, user_name, hashed_password
    from some_table
    where id = #{id}
  </select>

 

 

3.3)鑒別器:

有時一個單獨的數據庫查詢也許返回很多不同 (但是希望有些關聯) 數據類型的結果集。鑒別器元素就是被設計來處理這個情況的, 還有包括類的繼承層次結構。鑒別器非常容易理解,因為它的表現很像 Java 語言中的 switch 語句。

定義鑒別器指定了 column 和 javaType 屬性。列是 MyBatis 查找比較值的地方。 JavaType 是需要被用來保證等價測試的合適類型(盡管字符串在很多情形下都會有用)

<?xml version="1.0" encoding="utf-8"?>
<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id"/> 
  <result property="vin" column="vin"/> 
  <result property="year" column="year"/> 
  <result property="make" column="make"/> 
  <result property="model" column="model"/> 
  <result property="color" column="color"/> 
  <discriminator javaType="int" column="vehicle_type">
    <case value="1" resultType="carResult">
      <result property="doorCount" column="door_count"/>
    </case> 
    <case value="2" resultType="truckResult">
      <result property="boxSize" column="box_size"/> 
      <result property="extendedCab" column="extended_cab"/>
    </case> 
    <case value="3" resultType="vanResult">
      <result property="powerSlidingDoor" column="power_sliding_door"/>
    </case> 
    <case value="4" resultType="suvResult">
      <result property="allWheelDrive" column="all_wheel_drive"/>
    </case>
  </discriminator>
</resultMap>
 

3. 高級結果映射

 比如,我們如何映射下面這個語句?

<!-- Very Complex Statement -->
<select id="selectBlogDetails" parameterType="int" resultMap="detailedBlogResultMap"> select B.id as blog_id, B.title as blog_title, B.author_id as blog_author_id, A.id as author_id, A.username as author_username, A.password as author_password, A.email as author_email, A.bio as author_bio, A.favourite_section as author_favourite_section, P.id as post_id, P.blog_id as post_blog_id, P.author_id as post_author_id, P.created_on as post_created_on, P.section as post_section, P.subject as post_subject, P.draft as draft, P.body as post_body, C.id as comment_id, C.post_id as comment_post_id, C.name as comment_name, C.comment as comment_text, T.id as tag_id, T.name as tag_name from Blog B left outer join Author A on B.author_id = A.id left outer join Post P on B.id = P.blog_id left outer join Comment C on P.id = C.post_id left outer join Post_Tag PT on PT.post_id = P.id left outer join Tag T on PT.tag_id = T.id where B.id = #{id}</select>

下面是一個完整的復雜結果映射例子 (假設作者, 博客, 博文, 評論和標簽都是類型的別名) 我們來看看, 。但是不用緊張, 我們會一步一步來說明。當天最初它看起來令人生畏,但實際上非常簡單。

<?xml version="1.0" encoding="utf-8"?>
 
<!-- Very Complex Result Map -->
<resultMap id="detailedBlogResultMap" type="Blog">
  <constructor>
    <idArg column="blog_id" javaType="int"/>  (對應實體中的 有參構造函數)
  </constructor> 
  <result property="title" column="blog_title"/> 
  <association property="author" javaType=" Author"> (association 專門負責描述一對一的關系)
    <id property="id" column="author_id"/> 
    <result property="username" column="author_username"/> 
    <result property="password" column="author_password"/> 
    <result property="email" column="author_email"/> 
    <result property="bio" column="author_bio"/> 
    <result property="favouriteSection" column="author_favourite_section"/>
  </association> 
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/> 
    <result property="subject" column="post_subject"/> 
    <association property="author" javaType="Author"/> 
    <collection property="comments" ofType=" Comment">
      <id property="id" column="comment_id"/>
    </collection> 
    <collection property="tags" ofType=" Tag">
      <id property="id" column="tag_id"/>
    </collection> 
    <discriminator javaType="int" column="draft"> (鑒別器:switch)
      <case value="1" resultType="DraftPost"/>
    </discriminator>
  </collection>
</resultMap>

resultMap :

  • constructor - 類在實例化時,用來注入結果到構造方法中id – 一個 ID 結果;標記結果作為 ID 可以幫助提高整體效能
    • idArg - ID 參數;標記結果作為 ID 可以幫助提高整體效能
    • arg - 注入到構造方法的一個普通結果
  • result – 注入到字段或 JavaBean 屬性的普通結果
  • association – 一個復雜的類型關聯;許多結果將包成這種類型
    • 嵌入結果映射 – 結果映射自身的關聯,或者參考一個
  • collection – 復雜類型的集
    • 嵌入結果映射 – 結果映射自身的集,或者參考一個
  • discriminator – 使用結果值來決定使用哪個結果映射
    • case – 基於某些值的結果映射
      • 嵌入結果映射 – 這種情形結果也映射它本身,因此可以包含很多相 同的元素,或者它可以參照一個外部的結果映射。

最佳實踐 通常逐步建立結果映射。單元測試的真正幫助在這里。如果你嘗試創建一次創建一個向上面示例那樣的巨大的結果映射, 那么可能會有錯誤而且很難去控制它來工作。開始簡單一些,一步一步的發展。而且要進行單元測試!使用該框架的缺點是它們有時是黑盒(是否可見源代碼) 。你確定你實現想要的行為的最好選擇是編寫單元測試。它也可以你幫助得到提交時的錯誤。


免責聲明!

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



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