mybatis多表關聯查詢及高級映射

轉自:https://blog.csdn.net/hefenglian/article/details/80699723

訂單商品數據模型

這裏寫圖片描述
1.1 數據模型分析思路
1、每張表記錄的數據內容
2、每張表重要的字段設置(非空字段、外鍵字段)
3、數據庫級別表與表之間的關係(外鍵關係)
4、表與表之間的業務關係(建立在某個業務意義基礎上去分析)
1.2 數據模型分析
這裏寫圖片描述
用戶表user:
記錄了購買商品的用戶信息

訂單表:orders
記錄了用戶所創建的訂單(購買商品的訂單)

訂單明細表:orderdetail:
記錄了訂單的詳細信息即購買商品的信息

商品表:items
記錄了商品信息

orders和user:
orders—>user:一個訂單隻由一個用戶創建,一對一
user—->orders:一個用戶可以創建多個訂單,一對多

orders和orderdetail:
orders—>orderdetail:一個訂單可以包括 多個訂單明細,因爲一個訂單可以購買多個商品,每個商品的購買信息在orderdetail記錄,一對多關係
orderdetail–> orders:一個訂單明細只能包括在一個訂單中,一對一

orderdetail和items:
orderdetail—>itesms:一個訂單明細只對應一個商品信息,一對一
items–> orderdetail:一個商品可以包括在多個訂單明細 ,一對多

再分析數據庫級別沒有關係的表之間是否有業務關係:
orders和items:
orders和items之間可以通過orderdetail表建立 關係。

一對一關聯映射

需求:查詢訂單信息,關聯查詢創建訂單的用戶信息
方式一:resultType
第一步:創建pojo—->OrdersCustom

/ * 作用:將sql查詢的 訂單orders和用戶user結果集 全部成功映射到 pojo中,
 但是Orders.java中屬性包含不全,因此在寫一個pojo類在繼承Orders基礎上,補充添加其它屬性信息,
 注意讓此類繼承包括字段較多的pojo類,比如這裏繼承Orders而不是user,
因爲查詢結果集中user屬性全部有5個,Orders只有3*/
package cn.itcast.mybatis.pojo;
public class OrdersCustom extends Orders{
    //繼承Orders是爲了補充添加以下用戶屬性
        /*USER.username,
          USER.sex,
          USER.address */
    private String username;
    private String sex;
    private String address;

    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getSex() {
        return sex;
    } 
    public void setSex(String sex) {
        this.sex = sex;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
}

第二步:在OrdersMapperCustom.xml中添加如下sql語句

確定查詢的主表:訂單表
確定查詢的關聯表:用戶表
關聯查詢使用內鏈接?還是外鏈接?
:由於orders表中有一個外鍵(user_id),通過外鍵關聯查詢用戶表只能查詢出一條記錄,可以使用內鏈接。

<!-- 第一種:resultType:查詢訂單關聯查詢用戶信息 -->
    <select id="findOrderUser" resultType="cn.itcast.mybatis.pojo.OrdersCustom">
    SELECT
        orders.* ,
        USER.username,
        USER.sex,
        USER.address
    FROM
        orders,  
        USER 
    where 
        orders.user_id=user.id
    </select>

第三步:在接口OrdersMapperCustom.java中添加

    //查詢訂單關聯查詢用戶信息
    public List<OrdersCustom>findOrderUser()throws Exception;

第四步:在OrdersMapperCustomTest.java中添加測試

@Test
    public void testFindOrdersUser() throws Exception {
        //得到會話sqlSession
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //創建代理對象
        OrdersMapperCustom ordersMapperCustom=sqlSession.getMapper(OrdersMapperCustom.class);
        //調用mapper的方法
        List<OrdersCustom>list=ordersMapperCustom.findOrderUser();
        System.out.println(list); 
        sqlSession.close();
    }

方式二:resultMap
第一步:創建pojo—->OrdersCustom(同上)
第二步:在OrdersMapperCustom.xml中添加如下配置語句

<!-- 定義一個resultMap,訂單查詢 關聯 用戶的 ,將整個查詢的結果映射到cn.itcast.mybatis.pojo.Orders中-->
<resultMap type="cn.itcast.mybatis.pojo.Orders" id="OrdersUserResultMap">

<!-- (1) 配置訂單信息 -->
        <!--  數據庫表orders對應 pojo中的Orders.java -->
<!--  id:唯一標識
         column:訂單信息的唯 一標識 列
         property:訂單信息的唯 一標識 列所映射到Orders中哪個屬性
      result:普通標識   -->

    <id column="id" property="id"/>
    <result column="user_id" property="userId"/> 
    <result column="number" property="number"/>
    <result column="createtime" property="createtime"/>
    <result column="note" property="note"/>

<!-- (2)配置關聯用戶信息 -->
      <!--   數據庫表user對應 pojo中的User.java -->
<!-- association:用於映射關聯查詢單個對象的信息
            property:要將關聯查詢的用戶信息映射到Orders中哪個屬性
            javaType:映射到user的哪個屬性-->

  <association property="user"  javaType="cn.itcast.mybatis.pojo.User">
            <!-- id:關聯查詢用戶的唯 一標識
                   column:指定唯 一標識用戶信息的列
                 result:普通標識
             -->
            <id column="user_id" property="id"/> 
            <result column="username" property="username"/>
            <result column="sex" property="sex"/>
            <result column="address" property="address"/>   
  </association> 
</resultMap>

 <!--第二種:舉例一對一: ResultMap:查詢訂單關聯查詢用戶信息 -->
 <select id="findOrdersUserResultMap" resultMap="OrdersUserResultMap">
    SELECT
        orders.* ,
        USER.username,
        USER.sex,
        USER.address
    FROM
        orders,
        USER 
    WHERE 
        orders.user_id=user.id
</select>

第三步:在接口OrdersMapperCustom.java中添加

//可查詢訂單關聯查詢用戶使用resultMap
public List<Orders>findOrdersUserResultMap()throws Exception;

第四步:在OrdersMapperCustomTest.java中測試

@Test
    public void testFindOrdersUserResultMap() throws Exception {
        //得到會話sqlSession
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //創建代理對象
        OrdersMapperCustom ordersMapperCustom=sqlSession.getMapper(OrdersMapperCustom.class);
        //調用mapper的方法,返回映射在pojo 中Orders(裏面補充了User user)
        List<Orders>list=ordersMapperCustom.findOrdersUserResultMap();
        System.out.println(list); 
        sqlSession.close();
    }

resultType和resultMap實現一對一查詢小結
實現一對一查詢:
resultType:使用resultType實現較爲簡單,如果pojo中沒有包括查詢出來的列名,需要增加列名對應的屬性,即可完成映射。
如果沒有查詢結果的特殊要求建議使用resultType。

resultMap:需要單獨定義resultMap,實現有點麻煩,如果對查詢結果有特殊的要求,使用resultMap可以完成將關聯查詢映射pojo的屬性中。

resultMap可以實現延遲加載,resultType無法實現延遲加載。

一對多關聯映射

需求:查詢訂單orders關聯的訂單明細信息orderdetails
第一步:創建pojo—->Orders.java

//表orders
public class Orders {
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;

    //添加user用戶屬性信息,將關聯的用戶信息映射到pojo(User user)的屬性中
    private User user;

    //添加訂單明細 Orderdetail的屬性信息,將關聯的訂單明細信息映射到此order類
    private List<Orderdetail>orderdetails;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public Integer getUserId() {
        return userId;
    }
    public void setUserId(Integer userId) {
        this.userId = userId;
    }
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number == null ? null : number.trim();
    }
    public Date getCreatetime() {
        return createtime;
    }
    public void setCreatetime(Date createtime) {
        this.createtime = createtime;
    }
    public String getNote() {
        return note;
    }
    public void setNote(String note) {
        this.note = note == null ? null : note.trim();
    } 
    //用戶的getter setter方法
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user; 
    }
    //添加訂單明細的getter setter方法
    public List<Orderdetail> getOrderdetails() {
        return orderdetails;
    }
    public void setOrderdetails(List<Orderdetail> orderdetails) {
        this.orderdetails = orderdetails;
    }
}

使用resultType將上邊的 查詢結果映射到pojo中,訂單信息的就是重複。
對orders映射不能出現重複記錄。

在orders.java類中添加List<orderDetail>orderDetails屬性。
最終會將訂單信息映射到orders中,訂單所對應的訂單明細映射到orders中的orderDetails屬性中。

第二步:在OrdersMapperCustom.xml中添加如下配置語句
sql語句:
確定主查詢表:訂單表
確定關聯查詢表:訂單明細表
在一對一查詢基礎上添加訂單明細表關聯即可。

<!-- 訂單及訂單明細的resultMap,其中(1)(2)和上面一樣,可以採用繼承 -->
<resultMap type="cn.itcast.mybatis.pojo.Orders" id="OrdersAndOrderDetailResultMap"
extends="OrdersUserResultMap">
<!-- (1) 配置訂單信息 -->
         <!--  數據庫表orders對應 pojo中的Orders.java -->
<!-- (2) 配置關聯用戶信息 -->     
        <!--  數據庫表user對應 pojo中的User.java -->
<!-- (3) 配置訂單明細信息 -->
         <!-- 數據庫表orderdetail對應 pojo中的Orderdetail.java -->

    <!-- 由於一條訂單關聯查詢多個訂單明細,因此採用collection集合映射 
    collection:將關聯查詢到的多條記錄映射到集合對象中
    property:將關聯查詢到的多條記錄映射到cn.itcast.mybatis.pojo.Orders中那個屬性中
    ofType:指定映射到list集合屬性中pojo的類型-->

    <collection property="orderdetails" ofType="cn.itcast.mybatis.pojo.Orderdetail">
        <id column="orderdetail_id" property="id"/>
        <result column="items_id" property="itemsId"/>
        <result column="items_num" property="itemsNum"/>
        <result column="orders_id" property="ordersId"/>
    </collection>     
</resultMap>


<!--舉例一對多: ResultMap:查詢 訂單 關聯 訂單明細 信息 -->
 <select id="findOrdersAndOrderDetailResultMap" resultMap="OrdersAndOrderDetailResultMap">
    SELECT
        orders.* ,
        USER.username,
        USER.sex,
        USER.address,
        orderdetail.id orderdetail_id,<!--別名-->
        orderdetail.orders_id,
        orderdetail.items_id,
        orderdetail.items_num
    FROM
        orders,
        USER,
        orderdetail 
    WHERE 
        orders.user_id=user.id AND orderdetail.orders_id=orders.id
</select>

第三步:在接口OrdersMapperCustom.java中添加

//查詢訂單關聯訂單明細信息
public List<Orders>findOrdersAndOrderDetailResultMap()throws Exception;

第四步:在OrdersMapperCustomTest.java中添加測試代碼:

@Test
    public void testFindOrdersAndOrderDetailResultMap() throws Exception {
        //得到會話sqlSession
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //創建代理對象
        OrdersMapperCustom ordersMapperCustom=sqlSession.getMapper(OrdersMapperCustom.class);
        //調用mapper的方法,返回映射在pojo 中Orders(裏面補充了Orderdetail orderDetails)
        List<Orders>list=ordersMapperCustom.findOrdersAndOrderDetailResultMap();
        System.out.println(list); 
        sqlSession.close();
    }

多對多關聯映射

需求:查詢用戶及用戶購買商品信息。

第一步:創建pojo—->User.java,Orders.java,Orderdetail.java,Items.java
映射思路:

  • 將用戶信息映射到user中
  • 在user類中添加訂單列表屬性private List<Orders>orderList;,將用戶創建的訂單映射到ordersList
  • 在Orders中添加訂單明細列表屬性
    private List<Orderdetail>orderdetails;,將訂單的明細映射到orderdetails
  • 在Orderdetail中添加Items屬性private Items items,將訂單明細所對應的商品映射到Items

第二步:在OrdersMapperCustom.xml中添加如下配置語句

<!-- 查詢用戶和購買商品的resultMap -->
<resultMap type="cn.itcast.mybatis.pojo.User" id="UserAndItemsResultMap">
<!-- (1) 配置用戶信息 --> 
        <id column="user_id" property="id"/>
        <result column="username" property="username"/>
        <result column="sex" property="sex"/>
        <result column="address" property="address"/>       
<!-- (2) 配置訂單信息
        一個用戶對應多個訂單,使用collection映射 -->     
 <collection property="orderList" ofType="cn.itcast.mybatis.pojo.Orders">
        <id column="id" property="id"/>
        <result column="user_id" property="userId"/>
        <result column="number" property="number"/>
        <result column="createtime" property="createtime"/>
        <result column="note" property="note"/>
    <!-- (3) 配置訂單明細信息  
                                     一個訂單包括 多個訂單明細 -->       
    <collection property="orderdetails" ofType="cn.itcast.mybatis.pojo.Orderdetail">
            <id column="orderdetail_id" property="id"/>
            <result column="items_id" property="itemsId"/>
            <result column="items_num" property="itemsNum"/>
            <result column="orders_id" property="ordersId"/>        
            <!-- (4) 配置商品信息
                                                  一個訂單明細對應一個商品-->
            <association property="items" javaType="cn.itcast.mybatis.pojo.Items">
                <id column="items_id" property="id"/>
                <result column="items_name" property="name"/>
                <result column="items_detail" property="detail"/>
                <result column="items_price" property="price"/>
            </association>           
    </collection>  
</collection>

</resultMap>


<!-- 舉例多對多:ResultMap:查詢 用戶 購買的商品信息 -->
<select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">
    SELECT 
      orders.*,
      USER.username,
      USER.sex,
      USER.address,

      orderdetail.id orderdetail_id,
      orderdetail.items_id,
      orderdetail.items_num,
      orderdetail.orders_id,

      items.name items_name,
      items.detail items_detail,
      items.price items_price
    FROM
      orders,
      USER,
      orderdetail,
      items
    WHERE 
        orders.user_id = user.id AND orderdetail.orders_id=orders.id 
        AND orderdetail.items_id=items.id
</select>

第三步:在接口OrdersMapperCustom.java中添加

//查詢用戶購買的商品信息
public List<User>findUserAndItemsResultMap()throws Exception;

第四步:在OrdersMapperCustomTest.java中測試

@Test
    public void testFindUserAndItemsResultMap() throws Exception {
        //得到會話sqlSession
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //創建代理對象
        OrdersMapperCustom ordersMapperCustom=sqlSession.getMapper(OrdersMapperCustom.class);
        //調用mapper的方法,返回映射在pojo 中Orders(裏面補充了Orderdetail orderdetails)
        List<User>list=ordersMapperCustom.findUserAndItemsResultMap();
        System.out.println(list); 
        sqlSession.close();
    }

延遲加載

定義
resultMap可以實現高級映射(使用association、collection實現一對一及一對多映射),association、collection具備延遲加載功能。

延遲加載:先從單表查詢、需要時再從關聯表去關聯查詢,大大提高 數據庫性能,因爲查詢單表要比關聯查詢多張錶速度要快。

如果查詢訂單並且關聯查詢用戶信息。如果先查詢訂單信息即可滿足要求,當我們需要查詢用戶信息時再查詢用戶信息。把對用戶信息的按需去查詢就是延遲加載。
驗證步驟
需求:查詢訂單並且關聯查詢用戶信息,使用association實現延遲加載

0步:在SqlMapConfig.xml中開啓延遲加載
mybatis默認沒有開啓延遲加載,需要在SqlMapConfig.xml中setting配置

<settings>
        <!-- 開啓延遲加載,注意必須寫在前面 -->
            <!-- 打開延遲加載開關 -->
            <setting name="lazyLoadingEnabled" value="true"/>
            <!-- 將積極加載改爲消極加載即是按需加載 -->
            <setting name="aggressiveLazyLoading" value="false"/>

</settings>

步:創建pojo—->Orders.java(同上一對一查詢)

步:在OrdersMapperCustom.xml中添加如下配置語句

先去執行findOrdersUserLazyLoading,當需要去查詢用戶信息的時候再去執行findUserById,通過resultMap的定義將延遲加載執行配置起來。

<resultMap type="cn.itcast.mybatis.pojo.Orders" id="OrdersUserLazyLoadingResultMap">
<!-- (1) 配置訂單信息 -->
        <id column="id" property="id"/>
        <result column="user_id" property="userId"/>
        <result column="number" property="number"/>
        <result column="createtime" property="createtime"/>
        <result column="note" property="note"/>
<!-- (2) 實現用戶信息延遲加載 -->  
<!-- select:指定延遲加載需要執行的statement的id(是根據user_id查詢用戶信息的statement),
                                要使用userMapper.xml中findUserById完成根據用戶id(user_id)用戶信息的查詢,
                                如果findUserById不在本mapper中,則需要加上所在的namespace
           <select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.pojo.User">
                SELECT*FROM USER WHERE id=#{id}
           </select>                          
     column:訂單信息中關聯用戶信息查詢的列,是user_id

             關聯查詢的sql理解爲:子查詢
     select 
           orders.*,
          (select username from user where orders.user_id=user.id)username,
          (select sex from user where orders.user_id=user.id)sex
     from 
          orders 
 -->

       <association property="user" javaType="cn.itcast.mybatis.pojo.User"
                    select="cn.itcast.mybatis.mapper.UserMapper.findUserById" 
                    column="user_id">
       </association>
</resultMap>


<select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingResultMap">
SELECT *FROM orders
</select>
  • 關聯查詢用戶信息
    通過上邊查詢到的訂單信息中user_id去關聯查詢用戶信息
    使用UserMapper.xml中的findUserById
<select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.pojo.User">
SELECT*FROM USER WHERE id=#{id}
</select>

第三步:在接口OrdersMapperCustom.java中添加

//查詢訂單關聯查詢用戶,用戶信息是延遲加載
public List<Orders>findOrdersUserLazyLoading()throws Exception;

第四步:測試

//實現訂單查詢用戶,用戶信息的延遲加載
    @Test
    public void testFindOrdersUserLazyLoading() throws Exception {
        //得到會話sqlSession
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //創建代理對象
        OrdersMapperCustom ordersMapperCustom=sqlSession.getMapper(OrdersMapperCustom.class);
        //查詢訂單信息(單表)
        List<Orders>list=ordersMapperCustom.findOrdersUserLazyLoading();
        //遍歷訂單列表
        for(Orders orders:list){
            //執行Orders裏面的getUser()時纔去查詢用戶信息,這裏實現按需加載了
            User user=orders.getUser();
            System.out.println(user);
        }
    }

測試思路:
1、執行上邊mapper方法(findOrdersUserLazyLoading),內部去調用cn.itcast.mybatis.mapper.OrdersMapperCustom中的findOrdersUserLazyLoading只查詢orders信息(單表)。

2、在程序中去遍歷上一步驟查詢出的List<Orders>,當我們調用Orders中的getUser方法時,開始進行延遲加載。

3、延遲加載,去調用UserMapper.xml中findUserbyId這個方法獲取用戶信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章