Mybatis (三) Mybatis映射文件

Mybatis映射文件

基本CRUD

增長

<select id="saveRole" resultType="role">
  insert into tb_role
  (
  <trim suffixOverrides=",">
    <if test="roleName!=null">
      role_name,
    </if>
    <if test="description != null">
      description,
    </if>
    <if test="status != null">
      status,
    </if>
    <if test="createTime != null">
      create_time,
    </if>
    <if test="createUser != null">
      create_user,
    </if>
    <if test="modifyTime != null">
      modify_time,
    </if>
    <if test="modifyUser != null">
      modify_user
    </if>
  </trim>
  ) VALUES
  (
  <trim suffixOverrides=",">
    <if test="roleName!=null">
      #{roleName},
    </if>
    <if test="description != null">
      #{description},
    </if>
    <if test="status != null">
      #{status},
    </if>
    <if test="createTime != null">
      #{createTime},
    </if>
    <if test="createUser != null">
      #{createUser},
    </if>
    <if test="modifyTime != null">
      #{modifyTime},
    </if>
    <if test="modifyUser != null">
      #{modifyUser}
    </if>
  </trim>
  )
</select>

這個增長方法使用if 進行判斷,因此只是將不爲空的字段添加。java

增長並返回ID

<!--設置保存的時候須要返回插入時的id-->
<insert id="saveUser" useGeneratedKeys="true" keyProperty="id" parameterType="User" >
    insert into tb_user (user_id,
        username,password,email,phone,gender,birthday,create_time,
        create_user,modify_time,modify_user)
    values (
        #{user.userId},#{user.username},#{user.password},#{user.email},#{user.phone},#{user.gender},
        #{user.birthday},#{user.createTime},#{user.createUser},#{user.modifyTime},#{user.modifyUser})
</insert>

刪除

<delete id="deleteRoleById">
  delete from tb_role where id = #{id}
</delete>

這是一個很是簡單的刪除語句,這裏不贅述。git

更新

<update id="updateRole">
  update tb_role
  <set>
    <if test="roleName!=null">
      role_name = #{roleName},
    </if>
    <if test="description != null">
      description = #{description},
    </if>
    <if test="status != null">
      status = #{status},
    </if>
    <if test="createTime != null">
      create_time = #{createTime},
    </if>
    <if test="createUser != null">
      create_user = #{createUser},
    </if>
    <if test="modifyTime != null">
      modify_time = #{modifyTime},
    </if>
    <if test="modifyUser != null">
      modify_user = #{modifyUser}
    </if>
  </set>
  where id = #{id}
</update>

提示:這裏採用了選擇性更新,即只有字段不爲空的時候,纔會進行更新操做。sql

查詢

<select id="selectRolesByStatus" resultType="role">
  select * from tb_role where status = #{status}
</select>

提示:這裏僅僅介紹一下最簡單的查詢,後面重點介紹與查詢相關的。數據庫

增刪改查標籤相關屬性請參考:編程

https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#insert_update_and_deletejson

增刪改查標籤屬性

Select 元素的屬性

屬性 描述
id 在命名空間中惟一的標識符,能夠被用來引用這條語句。
parameterType 將會傳入這條語句的參數類的徹底限定名或別名。這個屬性是可選的,由於 MyBatis 能夠經過類型處理器(TypeHandler) 推斷出具體傳入語句的參數,默認值爲未設置(unset)。
resultType 從這條語句中返回的指望類型的類的徹底限定名或別名。 注意若是返回的是集合,那應該設置爲集合包含的類型,而不是集合自己。可使用 resultType 或 resultMap,但不能同時使用。
resultMap 外部 resultMap 的命名引用。結果集的映射是 MyBatis 最強大的特性,若是你對其理解透徹,許多複雜映射的情形都能迎刃而解。可使用 resultMap 或 resultType,但不能同時使用。
flushCache 將其設置爲 true 後,只要語句被調用,都會致使本地緩存和二級緩存被清空,默認值:false。
useCache 將其設置爲 true 後,將會致使本條語句的結果被二級緩存緩存起來,默認值:對 select 元素爲 true。
timeout 這個設置是在拋出異常以前,驅動程序等待數據庫返回請求結果的秒數。默認值爲未設置(unset)(依賴驅動)。
fetchSize 這是一個給驅動的提示,嘗試讓驅動程序每次批量返回的結果行數和這個設置值相等。 默認值爲未設置(unset)(依賴驅動)。
statementType STATEMENT,PREPARED 或 CALLABLE 中的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED。
resultSetType FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等價於 unset) 中的一個,默認值爲 unset (依賴驅動)。
databaseId 若是配置了數據庫廠商標識(databaseIdProvider),MyBatis 會加載全部的不帶 databaseId 或匹配當前 databaseId 的語句;若是帶或者不帶的語句都有,則不帶的會被忽略。
resultOrdered 這個設置僅針對嵌套結果 select 語句適用:若是爲 true,就是假設包含了嵌套結果集或是分組,這樣的話當返回一個主結果行的時候,就不會發生有對前面結果集的引用的狀況。 這就使得在獲取嵌套的結果集的時候不至於致使內存不夠用。默認值:false。
resultSets 這個設置僅對多結果集的狀況適用。它將列出語句執行後返回的結果集並給每一個結果集一個名稱,名稱是逗號分隔的。

Insert, Update, Delete 元素的屬性

屬性 描述
id 命名空間中的惟一標識符,可被用來表明這條語句。
parameterType 將要傳入語句的參數的徹底限定類名或別名。這個屬性是可選的,由於 MyBatis 能夠經過類型處理器推斷出具體傳入語句的參數,默認值爲未設置(unset)。
parameterMap 這是引用外部 parameterMap 的已經被廢棄的方法。請使用內聯參數映射和 parameterType 屬性。
flushCache 將其設置爲 true 後,只要語句被調用,都會致使本地緩存和二級緩存被清空,默認值:true(對於 insert、update 和 delete 語句)。
timeout 這個設置是在拋出異常以前,驅動程序等待數據庫返回請求結果的秒數。默認值爲未設置(unset)(依賴驅動)。
statementType STATEMENT,PREPARED 或 CALLABLE 的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED。
useGeneratedKeys (僅對 insert 和 update 有用)這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由數據庫內部生成的主鍵(好比:像 MySQL 和 SQL Server 這樣的關係數據庫管理系統的自動遞增字段),默認值:false。
keyProperty (僅對 insert 和 update 有用)惟一標記一個屬性,MyBatis 會經過 getGeneratedKeys 的返回值或者經過 insert 語句的 selectKey 子元素設置它的鍵值,默認值:未設置(unset)。若是但願獲得多個生成的列,也能夠是逗號分隔的屬性名稱列表。
keyColumn (僅對 insert 和 update 有用)經過生成的鍵值設置表中的列名,這個設置僅在某些數據庫(像 PostgreSQL)是必須的,當主鍵列不是表中的第一列的時候須要設置。若是但願使用多個生成的列,也能夠設置爲逗號分隔的屬性名稱列表。
databaseId 若是配置了數據庫廠商標識(databaseIdProvider),MyBatis 會加載全部的不帶 databaseId 或匹配當前 databaseId 的語句;若是帶或者不帶的語句都有,則不帶的會被忽略。

結果映射

結果映射(resultMap)

  • constructor - 用於在實例化類時,注入結果到構造方法中idArg - ID 參數;標記出做爲 ID 的結果能夠幫助提升總體性能arg - 將被注入到構造方法的一個普通結果
  • id – 一個 ID 結果;標記出做爲 ID 的結果能夠幫助提升總體性能
  • result – 注入到字段或 JavaBean 屬性的普通結果
  • association – 一個複雜類型的關聯;許多結果將包裝成這種類型嵌套結果映射 – 關聯自己能夠是一個 resultMap 元素,或者從別處引用一個
  • collection – 一個複雜類型的集合嵌套結果映射 – 集合自己能夠是一個 resultMap 元素,或者從別處引用一個
  • discriminator – 使用結果值來決定使用哪一個 resultMapcase – 基於某些值的結果映射嵌套結果映射 – case 自己能夠是一個 resultMap 元素,所以能夠具備相同的結構和元素,或者從別處引用一個

Id 和 Result 的屬性

屬性 描述
property 映射到列結果的字段或屬性。若是用來匹配的 JavaBean 存在給定名字的屬性,那麼它將會被使用。不然 MyBatis 將會尋找給定名稱的字段。 不管是哪種情形,你均可以使用一般的點式分隔形式進行復雜屬性導航。 好比,你能夠這樣映射一些簡單的東西:「username」,或者映射到一些複雜的東西上:「address.street.number」。
column 數據庫中的列名,或者是列的別名。通常狀況下,這和傳遞給 resultSet.getString(columnName) 方法的參數同樣。
javaType 一個 Java 類的徹底限定名,或一個類型別名(關於內置的類型別名,能夠參考上面的表格)。 若是你映射到一個 JavaBean,MyBatis 一般能夠推斷類型。然而,若是你映射到的是 HashMap,那麼你應該明確地指定 javaType 來保證行爲與指望的相一致。
jdbcType JDBC 類型,所支持的 JDBC 類型參見這個表格以後的「支持的 JDBC 類型」。 只須要在可能執行插入、更新和刪除的且容許空值的列上指定 JDBC 類型。這是 JDBC 的要求而非 MyBatis 的要求。若是你直接面向 JDBC 編程,你須要對可能存在空值的列指定這個類型。
typeHandler 咱們在前面討論過默認的類型處理器。使用這個屬性,你能夠覆蓋默認的類型處理器。 這個屬性值是一個類型處理器實現類的徹底限定名,或者是類型別名。

支持的 JDBC 類型

爲了之後可能的使用場景,MyBatis 經過內置的 jdbcType 枚舉類型支持下面的 JDBC 類型。緩存

BIT FLOAT CHAR TIMESTAMP OTHER UNDEFINED
TINYINT REAL VARCHAR BINARY BLOB NVARCHAR
SMALLINT DOUBLE LONGVARCHAR VARBINARY CLOB NCHAR
INTEGER NUMERIC DATE LONGVARBINARY BOOLEAN NCLOB
BIGINT DECIMAL TIME NULL CURSOR ARRAY

單表基本結果映射

屬性設值

<resultMap id="base_map" type="role">
  <id column="id" jdbcType="INTEGER" property="id" />
  <result column="role_name" jdbcType="VARCHAR" property="roleName"/>
  <result column="description" jdbcType="VARCHAR" property="description"/>
  <result column="status" jdbcType="INTEGER" property="status"/>
  <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
  <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
  <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
  <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
</resultMap>

<select id="selectAllRoles" resultMap="base_map">
  select * from tb_role
</select>

java實體:mybatis

//空參數,全參數,get,set,toString
public class Role implements Serializable {

    private Integer id;
    private String roleName;
    private String description;
    private Integer status;
    private Date createTime;
    private String createUser;
    private Date modifyTime;
    private String modifyUser;
}

提示:能夠看出,這裏咱們再也不直接使用了user做爲返回類型(resultType),而是使用告終果映射(resultMap)來映射實體。以上方式使用的實體映射是使用的setter進行設置參數的。咱們在setId方法上加一段輸入語句以後,再次運行,結果以下:app

public void setId(Integer id) {
  System.out.println("setId of role is running");
  this.id = id;
}

那麼咱們如何使用構造函數來進行屬性設置賦值呢?

<resultMap id="base_map" type="role">
  <constructor>
    <idArg column="id" javaType="Integer"/>
    <arg column="role_name" javaType="String"/>
    <arg column="description" javaType="String"/>
    <arg column="status" javaType="Integer"/>
    <arg column="create_time" javaType="Date"/>
    <arg column="create_user" javaType="String"/>
    <arg column="modify_time" javaType="Date" />
    <arg column="modify_user" javaType="String" />
  </constructor>
</resultMap>

構造方法設值

public Role(Integer id, String roleName, String description, Integer status, Date createTime, String createUser, Date modifyTime, String modifyUser) {
  System.out.println("all args' constructor of role is running ");
  this.id = id;
  this.roleName = roleName;
  this.description = description;
  this.status = status;
  this.createTime = createTime;
  this.createUser = createUser;
  this.modifyTime = modifyTime;
  this.modifyUser = modifyUser;
}

測試結果:

關聯關係一對一

​ 前面咱們看到了單表操做,咱們經過直接返回對象或是使用resultMap的方式來映射實體。這裏咱們看一下實體一對一的關係如何映射。

一對一關係的映射:association標籤的屬性元素

property CDATA              屬性,必須
column CDATA                數據庫表的字段名
javaType CDATA              屬性的java類型
jdbcType CDATA              數據庫表的字段的類型
select CDATA                嵌套查詢時使用。
resultMap CDATA             關聯外部的手動映射關係時使用
typeHandler CDATA           類型處理器
notNullColumn CDATA     
columnPrefix CDATA          字段前綴,一對一中有涉及到
resultSet CDATA         
foreignColumn CDATA     
autoMapping (true|false)    是否自定映射
fetchType (lazy|eager)      是否懶加載

業務:用戶與身份證是一對一的關係。

User類:

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class User implements Serializable {

    private Integer id;
    private String userId;
    private String username;
    private String password;
    private String email;
    private String phone;
    private Integer gender;
    private Date birthday;
    private Integer status;
    private Date createTime;
    private String createUser;
    private Date modifyTime;
    private String modifyUser;
    private Card card;
}

提示:這裏使用了lombok 簡化實例開發,依賴以下:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
</dependency>

Card類:

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Card implements Serializable {

    private Integer id;
    private Integer uid;
    private String cardId;
    private String address;
    private Date createTime;
    private Date modifyTime;
}

一對一自動映射

​ 經過上面的實例類關係咱們能夠發現,card是User類中的一個屬性,可是如何經過Mybatis的自動映射機制將card表中的數據之間填充到User屬性中。咱們能夠在查詢字段上使用別名來映射,以下,uid字段是user的card屬性的屬性,則能夠經過card.uid 來映射到User類的card屬性的uid字段。

<select id="findUserWithCardByUserId" resultType="user">
    SELECT
      a.id,a.user_id,a.username,a.password,a.email,a.phone,
      a.gender,a.birthday,a.status,a.create_time,a.create_user,
      a.modify_time,a.modify_user,
      b.id as "card.id" ,
      b.uid as "card.uid",
      b.card_id as "card.cardId",
      b.address as "card.address",
      b.create_time as "card.createTime" ,
      b.modify_time as "card.modifyTime"
    FROM
        tb_user a
    INNER JOIN tb_card b on a.id = b.uid where a.id = #{id};
</select>

一對一手動映射

手動映射就是經過結果集的方式列進行映射,以下:

<resultMap id="BaseResultMapWithCard" type="user">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="user_id" jdbcType="VARCHAR" property="userId"/>
    <result column="username" jdbcType="VARCHAR" property="username"/>
    <result column="password" jdbcType="VARCHAR" property="password"/>
    <result column="email" jdbcType="VARCHAR" property="email"/>
    <result column="phone" jdbcType="VARCHAR" property="phone"/>
    <result column="gender" jdbcType="INTEGER" property="gender"/>
    <result column="birthday" jdbcType="DATE" property="birthday"/>
    <result column="status" jdbcType="INTEGER" property="status"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
    <association property="card" javaType="card">
        <id column="bid" jdbcType="INTEGER" property="id"/>
        <result column="uid" jdbcType="INTEGER" property="uid"/>
        <result column="card_id" jdbcType="VARCHAR" property="cardId"/>
        <result column="address" jdbcType="VARCHAR" property="address"/>
        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
        <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    </association>
</resultMap>


<select id="findUserWithCardByUserId" resultMap="BaseResultMapWithCard">
        select
            a.id,a.user_id,a.username,a.password,a.email,a.phone,a.gender,
            a.birthday,a.status,a.create_time,a.create_user,a.modify_time,a.modify_user,
            b.id bid,
            b.uid,
            b.card_id,
            b.address,
            b.create_time,
            b.modify_time
        FROM
            tb_user a
        INNER JOIN tb_card b on a.id = b.uid where a.id = #{id}
</select>

經過上述的SQL查詢和結果集的手動映射關係,這樣就能夠實現字段和實體的查詢了。

固然,Mybatis還提供下面這種方式來實現:

<resultMap id="BaseResultMapWithCard" type="user">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="user_id" jdbcType="VARCHAR" property="userId"/>
    <result column="username" jdbcType="VARCHAR" property="username"/>
    <result column="password" jdbcType="VARCHAR" property="password"/>
    <result column="email" jdbcType="VARCHAR" property="email"/>
    <result column="phone" jdbcType="VARCHAR" property="phone"/>
    <result column="gender" jdbcType="INTEGER" property="gender"/>
    <result column="birthday" jdbcType="DATE" property="birthday"/>
    <result column="status" jdbcType="INTEGER" property="status"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
    <association property="card" javaType="card" column="id" select="selectCard"></association>
</resultMap>

<select id="findUserWithCardByUserId" resultMap="BaseResultMapWithCard">
    select
      a.id,a.user_id,a.username,a.password,a.email,a.phone,a.gender,
      a.birthday,a.status,a.create_time,a.create_user,a.modify_time,a.modify_user
    FROM
        tb_user a
    where a.id = #{id}
</select>

<select id="selectCard" resultType="card">
    select * from tb_card where uid = #{id}
</select>

這樣的操做其實就是先查詢出User的信息,而後在取user表的id字段來查詢card表的數據,這樣就至關於向MySQL發送了兩條SQL,咱們經過日誌能夠觀察到現象:

​ 兩種方式均可以實現一樣地結果,若是須要控制SQL發送條數的話,可使用關聯方式,若是須要在必定程度上下降SQL的查詢時間,則能夠將其拆分爲多個查詢SQL。

拓展:

下面咱們看一下下面這個SQL如何進行映射,咱們假設,一個User有一個主身份證和一個副身份證,那麼咱們須要如何查詢映射:

User:

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class User implements Serializable {

    private Integer id;
    private String userId;
    private String username;
    private String password;
    private String email;
    private String phone;
    private Integer gender;
    private Date birthday;
    private Integer status;
    private Date createTime;
    private String createUser;
    private Date modifyTime;
    private String modifyUser;

    private Card card;//主
    private Card card1;//副
}

對應的SQL映射以下:

<resultMap id="BaseResultMapWithCard" type="user">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="user_id" jdbcType="VARCHAR" property="userId"/>
    <result column="username" jdbcType="VARCHAR" property="username"/>
    <result column="password" jdbcType="VARCHAR" property="password"/>
    <result column="email" jdbcType="VARCHAR" property="email"/>
    <result column="phone" jdbcType="VARCHAR" property="phone"/>
    <result column="gender" jdbcType="INTEGER" property="gender"/>
    <result column="birthday" jdbcType="DATE" property="birthday"/>
    <result column="status" jdbcType="INTEGER" property="status"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
    <association property="card" javaType="card" resultMap="cardResultMap" columnPrefix="b1_" />
    <association property="card1" javaType="card" resultMap="cardResultMap" columnPrefix="b2_" />
</resultMap>

<resultMap id="cardResultMap" type="card">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="uid" jdbcType="INTEGER" property="uid"/>
    <result column="card_id" jdbcType="VARCHAR" property="cardId"/>
    <result column="address" jdbcType="VARCHAR" property="address"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
</resultMap>


<select id="findUserWithCardByUserId" resultMap="BaseResultMapWithCard" >
    select
      a.id,a.user_id,a.username,a.password,a.email,a.phone,a.gender,
      a.birthday,a.status,a.create_time,a.create_user,a.modify_time,a.modify_user,
      b1.id b1_id,
      b1.uid b1_uid,
      b1.card_id b1_card_id,
      b1.address b1_address,
      b1.create_time b1_create_time,
      b1.modify_time b1_modify_time,
      b2.id b2_id,
      b2.uid b2_uid,
      b2.card_id b2_card_id,
      b2.address b2_address,
      b2.create_time b2_create_time,
      b2.modify_time b2_modify_time
    from tb_user a
    inner join tb_card b1 on a.id = b1.uid
    inner join tb_card b2 on a.id = b2.uid
    where a.id = 1
</select>

​ 當鏈接多個表時,咱們可能會不得不使用列別名來避免在 ResultSet 中產生重複的列名。指定 association標籤的columnPrefix 列名前綴容許你將帶有這些前綴的列映射到一個外部的結果映射中。

關聯關係一對多

// 下面是collection標籤的各個屬性元素

property CDATA #REQUIRED    必須,指定的是java實體類的屬性名
column CDATA                指定的是表的字段名(查詢出來的,有多是字段別名)
javaType CDATA              集合通常不使用這個
ofType CDATA                屬性的java類型,例如:string,integer
jdbcType CDATA              數據庫的字段類型
select CDATA                當咱們須要進行嵌套查詢的時候,執行另一個查詢語句
resultMap CDATA             返回值的映射關
typeHandler CDATA           類型處理
notNullColumn CDATA         
columnPrefix CDATA          當咱們須要進行區分的時候,能夠指定前綴,後面有案例
resultSet CDATA             
foreignColumn CDATA         外鍵
autoMapping (true|false)    是否須要自動映射
fetchType (lazy|eager)      是否進行懶加載

​ 在實際開發中,權限每每是無關業務,可是又是相當重要的一環。在設計權限的時候,咱們每每不會講權限之間與用戶以前關聯,爲了更加好的管理,咱們會在用戶與權限之間引入一個角色,用角色來統一管理具備相同權限的用戶,通常一個用戶存在於多個角色,好比即便CEO又是系統開發人員(哈哈),這裏就是一個一對多的關係,下面咱們看看,在Mybatis中一對多的關係如何映射:

User:

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class User implements Serializable {

    private Integer id;
    private String userId;
    private String username;
    private String password;
    private String email;
    private String phone;
    private Integer gender;
    private Date birthday;
    private Integer status;
    private Date createTime;
    private String createUser;
    private Date modifyTime;
    private String modifyUser;
    private List<Role> roles;
}

Role:

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Role implements Serializable {

    private Integer id;
    private String roleName;
    private String description;
    private Integer status;
    private Date createTime;
    private String createUser;
    private Date modifyTime;
    private String modifyUser;
}

根據id查詢的SQLxml文件:

這裏與前面的一對多的關聯關係有所不一樣 ,一對多關聯關係使用的是association,java類型使用的是javaType。而多對多關聯關係使用的標籤是collection,java類型屬性使用的是ofType。

<resultMap id="BaseResultWithRole" type="com.ooyhao.mybatis.bean.User">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="user_id" jdbcType="VARCHAR" property="userId"/>
    <result column="username" jdbcType="VARCHAR" property="username"/>
    <result column="password" jdbcType="VARCHAR" property="password"/>
    <result column="email" jdbcType="VARCHAR" property="email"/>
    <result column="phone" jdbcType="VARCHAR" property="phone"/>
    <result column="gender" jdbcType="INTEGER" property="gender"/>
    <result column="birthday" jdbcType="DATE" property="birthday"/>
    <result column="status" jdbcType="INTEGER" property="status"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
    <collection property="roles" ofType="role">
        <id column="cid" jdbcType="INTEGER" property="id"/>
        <result column="role_name" jdbcType="VARCHAR" property="roleName"/>
        <result column="description" jdbcType="VARCHAR" property="description"/>
        <result column="status" jdbcType="INTEGER" property="status"/>
        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
        <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
        <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
        <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
    </collection>
</resultMap>


<select id="findUserWithRolesByUserId" resultMap="BaseResultWithRole">
    select
      a.id,a.user_id,a.username,a.password,a.email,a.phone,a.gender,
      a.birthday,a.status,a.create_time,a.create_user,a.modify_time,a.create_user,
      c.id cid,
      c.role_name,
      c.description,
      c.status,
      c.create_time,
      c.create_user,
      c.modify_time,
      c.create_user
    from tb_user a
    left join tb_user_role b on a.id = b.user_id
    left join tb_role c on c.id = b.role_id
    where a.id = #{id}
</select>

測試結果以下:

{
    "birthday": 1551369600000,
    "createTime": 1551433926000,
    "createUser": "admin",
    "email": "12345678@qq.com",
    "gender": 1,
    "id": 1,
    "modifyTime": 1551679675000,
    "password": "admin123456789",
    "phone": "12345678901",
    "roles": [{
        "createTime": 1551433926000,
        "createUser": "admin",
        "description": "超級管理員",
        "id": 1,
        "modifyTime": 1551679675000,
        "roleName": "admin",
        "status": 0
    }, {
        "createTime": 1551433926000,
        "createUser": "admin",
        "description": "開發人員",
        "id": 2,
        "modifyTime": 1551679675000,
        "roleName": "develop",
        "status": 0
    }],
    "status": 0,
    "userId": "oms20190001",
    "username": "admin"
}

除了上述方式進行關聯查詢,咱們還能夠將SQL進行拆分:

關聯嵌套查詢:

<resultMap id="BaseResultWithRole" type="com.ooyhao.mybatis.bean.User">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="user_id" jdbcType="VARCHAR" property="userId"/>
    <result column="username" jdbcType="VARCHAR" property="username"/>
    <result column="password" jdbcType="VARCHAR" property="password"/>
    <result column="email" jdbcType="VARCHAR" property="email"/>
    <result column="phone" jdbcType="VARCHAR" property="phone"/>
    <result column="gender" jdbcType="INTEGER" property="gender"/>
    <result column="birthday" jdbcType="DATE" property="birthday"/>
    <result column="status" jdbcType="INTEGER" property="status"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
    <collection property="roles" ofType="role"  column="id"  select="selectRole" />
</resultMap>

<resultMap id="selectRole" type="role">
    <id column="cid" jdbcType="INTEGER" property="id"/>
    <result column="role_name" jdbcType="VARCHAR" property="roleName"/>
    <result column="description" jdbcType="VARCHAR" property="description"/>
    <result column="status" jdbcType="INTEGER" property="status"/>
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
    <result column="create_user" jdbcType="VARCHAR" property="createUser"/>
    <result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
    <result column="modify_user" jdbcType="VARCHAR" property="modifyUser"/>
</resultMap>


<select id="findUserWithRolesByUserId" resultMap="BaseResultWithRole">
    select
      a.id,a.user_id,a.username,a.password,a.email,a.phone,a.gender,
      a.birthday,a.status,a.create_time,a.create_user,a.modify_time,a.create_user
    from tb_user a
    where a.id = #{id}
</select>


<select id="selectRole" resultType="role" >
    select b.* from tb_user_role a
    left join tb_role b on a.role_id = b.id
    where a.user_id = #{id}
</select>

注:多對多其實就是雙向的一對多關係,再也不贅述。

鑑別器

摘自官網:

有時候,一個數據庫查詢可能會返回多個不一樣的結果集(但整體上仍是有必定的聯繫的)。 鑑別器(discriminator)元素就是被設計來應對這種狀況的,另外也能處理其它狀況,例如類的繼承層次結構。 鑑別器的概念很好理解——它很像 Java 語言中的 switch 語句。

一個鑑別器的定義須要指定 column 和 javaType 屬性。column 指定了 MyBatis 查詢被比較值的地方。 而 javaType 用來確保使用正確的相等測試(雖然不少狀況下字符串的相等測試均可以工做)。例如:

<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" resultMap="carResult"/>
    <case value="2" resultMap="truckResult"/>
    <case value="3" resultMap="vanResult"/>
    <case value="4" resultMap="suvResult"/>
  </discriminator>
</resultMap>
---------------------------------------也能夠這樣-----------------------------------------

<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>

提示:請注意,這些都是結果映射,若是你徹底不設置任何的 result 元素,MyBatis 將爲你自動匹配列和屬性。因此上面的例子大多都要比實際的更復雜。 這也代表,大多數數據庫的複雜度都比較高,咱們不太可能一直依賴於這種機制。

下面經過一個案例來使用一下鑑別器:

數據以下:

咱們經過接口的方式來使用鑑別器建立不一樣的交通工具實體:

public interface Vehicle {}

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Bus implements Vehicle {
    private Integer id;
    private String name;
}

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Car implements Vehicle{

    private Integer id;
    private String name;
}

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
public class Subway implements Vehicle {
    
    private Integer id;
    private String name;
}

Sql.xml文件:

<resultMap id="BaseResultMap" type="com.ooyhao.mybatis.bean.Vehicle">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <discriminator javaType="INTEGER" jdbcType="INTEGER" column="vehicle_type" >
        <case value="1" resultType="car">
             <result property="name" column="vehicle_name" jdbcType="VARCHAR" />
        </case>
        <case value="2" resultType="bus">
             <result property="name" column="vehicle_name" jdbcType="VARCHAR"/>
        </case>
        <case value="3" resultType="subway">
              <result property="name" column="vehicle_name" jdbcType="VARCHAR"/>
        </case>
    </discriminator>
</resultMap>

<select id="findVehicleById" resultMap="BaseResultMap">
    select * from tb_vehicle where id = #{id}
</select>

在case之外的,就至關於在每個case中都會存在,而在case中的則是根據條件來選擇的。

id爲1時:

id爲3時:

源碼地址:

https://gitee.com/ooyhao/JavaRepo_Public/tree/master/Mybatis

最後

若是以爲不錯的話,那就關注一下小編哦!一塊兒交流,一塊兒學習

相關文章
相關標籤/搜索