主頁 > 後端開發 > (九) MyBatis從入門到入土——延遲加載、鑒別器以及繼承

(九) MyBatis從入門到入土——延遲加載、鑒別器以及繼承

2021-02-24 06:12:20 後端開發

這是mybatis系列第9篇,沒看前文的建議先去【Java冢狐】公眾號中查看前文,方便理解和掌握,在上一篇中我們介紹了關于MyBatis的自動映射是如何開啟以及使用的,想必大家對于這方面的知識有所了解了,

今天要給大家帶來的主要是MyBatis延遲加載以及鑒別器相關方面的知識以及內容,

延遲加載

延遲加載介紹

所謂的延遲加載就是將資料加載時機推遲,其中比較典型的應用就是推遲嵌套查詢的執行時機,

因為在mybatis中經常用到關聯查詢,但是并不是任何時候都需要立即回傳關聯查詢結果,就比如查詢訂單資訊,并不一定需要及時回傳訂單對應的用戶資訊或者訂單詳情資訊等,所以當我們遇到這種情況時就需要一種機制,當需要查看關聯的資料時,再去執行對應的查詢,回傳需要的結果,

這種需求在mybatis中可以使用延遲加載機制來實作,

延遲加載2種設定方式

MyBatis對于延遲加載提供了兩種設定方式,分別是:

  • 全域配置的方式
  • sqlmap中配置的方式

從這兩種方式的名稱來看就能發現這兩種延遲加載的區別,第一種方法會對所有的關聯查詢有效,而第二種方法只會對相關設定的查詢有效,

下面我們就分別看一下這兩種延遲加載的使用方式,

全域配置延遲加載

要想實作全域配置延遲加載就要通過mybatis的組態檔,

mybatis組態檔中通過下面兩個屬性來控制延遲加載:

<settings>
    <!--打開延遲加載的開關  -->
    <setting name="lazyLoadingEnabled" value="https://www.cnblogs.com/javazhonghu/p/true"/>
    <!-- 當為true的時候,呼叫任意延遲屬性,會去加載所有延遲屬性,如果為false,則呼叫某個屬性的時候,只會加載指定的屬性 -->
    <setting name="aggressiveLazyLoading" value="https://www.cnblogs.com/javazhonghu/p/false"/>
</settings>
  • lazyLoadingEnabled:這個屬性比較好理解,是否開啟延遲加載,默認為false,如果需要開啟延遲加載,將其設定為true
  • aggressiveLazyLoading:當為true的時候,呼叫任意延遲屬性,會去加載所有延遲屬性,如果為false,則呼叫某個屬性的時候,只會加載指定的屬性

關于全域配置延遲加載的說明就是這些,下面我們來用一個具體的例子來說明下全域配置延遲加載是如何使用的,

需求

這次我們要使用MyBatis實作的需求就是通過訂單id查詢訂單的各種資訊,諸如:訂單用戶資訊、訂單明細串列,其中訂單用戶資訊和訂單明細資訊采用延遲加載的方式來進行獲取,

mybatis配置

按照前面的介紹第一步就是通過mybatis的組態檔來進行設定,如下所示:

<settings>
    <!--打開延遲加載的開關  -->
    <setting name="lazyLoadingEnabled" value="https://www.cnblogs.com/javazhonghu/p/true"/>
    <!-- 當為true的時候,呼叫任意延遲屬性,會去加載所有延遲屬性,如果為false,則呼叫某個屬性的時候,只會加載指定的屬性 -->
    <setting name="aggressiveLazyLoading" value="https://www.cnblogs.com/javazhonghu/p/true"/>
</settings>

OrderMapper.xml

進行全域配置的設定完畢以后,我們就進行我們正常開發的途徑,首先就是撰寫xml檔案,在xml檔案中撰寫我們的sql陳述句,

<resultMap id="orderModelMap1" type="com.zhonghu.chat09.demo5.model.OrderModel">
    <id column="id" property="id"/>
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <!--  通過訂單中user_id作為條件,查詢下單人資訊 -->
    <association property="userModel" select="com.zhonghu.chat09.demo5.mapper.UserMapper.getById1" column="user_Id"/>
    <!--  通過訂單id作為條件,查詢詳情串列 -->
    <collection property="orderDetailModelList" select="com.zhonghu.chat09.demo5.mapper.OrderDetailMapper.getListByOrderId1" column="id"/>
</resultMap>
<select id="getById1" resultMap="orderModelMap1">
    <![CDATA[
    SELECT
        a.id ,
        a.user_id,
        a.create_time,
        a.up_time
    FROM
        orders a
    WHERE
        a.id = #{value}
    ]]>
</select>

上面的orderModelMap1元素下面有兩個關聯查詢,我們也寫一下,

UserMapper.xml

<!-- 根據用戶id查詢用戶資訊 -->
<select id="getById1" resultType="com.zhonghu.chat09.demo5.model.UserModel">
    <![CDATA[
    SELECT id,name FROM user where id = #{user_id}
    ]]>
</select>

OrderDetailMapper.xml

<!-- 根據訂單di查詢訂單明細串列 -->
<select id="getListByOrderId1" resultType="com.zhonghu.chat09.demo5.model.OrderDetailModel">
    <![CDATA[
    SELECT
        a.id,
        a.order_id AS orderId,
        a.goods_id AS goodsId,
        a.num,
        a.total_price AS totalPrice
    FROM
        order_detail a
    WHERE
        a.order_id = #{order_id}
    ]]>
</select>

對應的3個Model

上面我們寫了三個xml,那么接來下我們撰寫一下xml對應的Model,

@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class OrderModel {
    private Integer id;
    private Integer userId;
    private Long createTime;
    private Long upTime;
    private UserModel userModel;
    //訂單詳情串列
    private List<OrderDetailModel> orderDetailModelList;
}

@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class UserModel {
    private Integer id;
    private String name;
}

@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class OrderDetailModel {
    private Integer id;
    private Integer orderId;
    private Integer goodsId;
    private Integer num;
    private Double totalPrice;
}

測驗用例

寫完了Model,我們的代碼基本就大功告成了,接下來我們就來看一看延遲加載的使用效果,

com.zhonghu.chat09.demo5.Demo5Test#getById1
@Test
public void getById1() throws IOException {
    //指定mybatis全域組態檔
    mybatisConfig = "demo5/mybatis-config.xml";
    this.before();
    OrderModel orderModel = null;
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        orderModel = mapper.getById1(1);
    }
    log.info("-------分割線--------");
    log.info("{}", orderModel.getUserModel());
}

運行輸出

01:55.343 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==>  Preparing: SELECT a.id , a.user_id, a.create_time, a.up_time FROM orders a WHERE a.id = ? 
01:55.372 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==> Parameters: 1(Integer)
01:55.431 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - <==      Total: 1
01:55.431 [main] INFO  c.j.chat05.demo5.Demo5Test - -------分割線--------
01:55.432 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - ==>  Preparing: SELECT a.id, a.order_id AS orderId, a.goods_id AS goodsId, a.num, a.total_price AS totalPrice FROM order_detail a WHERE a.order_id = ? 
01:55.432 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - ==> Parameters: 1(Integer)
01:55.435 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - <==      Total: 2
01:55.439 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ==>  Preparing: SELECT id,name FROM user where id = ? 
01:55.439 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ==> Parameters: 2(Integer)
01:55.441 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - <==      Total: 1
01:55.441 [main] INFO  c.j.chat05.demo5.Demo5Test - UserModel(id=2, name=Java冢狐)

從日志中可以看出,總共有3次查詢,后面2次查詢在分割線之后出現的,說明是呼叫了orderModel.getUserModel()觸發后面2次查詢動作,

代碼中我們呼叫的是獲取用戶資訊,而訂單串列資訊也被加載了,這個主要是由于aggressiveLazyLoading被設定為true了,當使用到一個延遲加載的屬性時,其他的延遲加載的屬性也會被一起加載,所以觸發了2個關聯的查詢,

下面我們看看將aggressiveLazyLoading設定為false的效果

<settings>
    <!--打開延遲加載的開關  -->
    <setting name="lazyLoadingEnabled" value="https://www.cnblogs.com/javazhonghu/p/true"/>
    <!-- 當為true的時候,呼叫任意延遲屬性,會去加載所有延遲屬性,如果為false,則呼叫某個屬性的時候,只會加載指定的屬性 -->
    <setting name="aggressiveLazyLoading" value="https://www.cnblogs.com/javazhonghu/p/false"/>
</settings>

再次運行測驗用例輸出

12:19.236 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==>  Preparing: SELECT a.id , a.user_id, a.create_time, a.up_time FROM orders a WHERE a.id = ? 
12:19.268 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==> Parameters: 1(Integer)
12:19.336 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - <==      Total: 1
12:19.337 [main] INFO  c.j.chat05.demo5.Demo5Test - -------分割線--------
12:19.338 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ==>  Preparing: SELECT id,name FROM user where id = ? 
12:19.338 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ==> Parameters: 2(Integer)
12:19.340 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - <==      Total: 1
12:19.341 [main] INFO  c.j.chat05.demo5.Demo5Test - UserModel(id=2, name=Java冢狐)

通過這兩次對比,我們可以很輕易的看出延遲加載開啟與否的效果區別,

sqlmap中設定延遲加載

上面的篇幅我們介紹了全域的延遲加載是如何起作用以及如何使用的,全域的方式會對所有的關聯查詢起效,影響范圍比較大,mybatis也提供了在關聯查詢中進行設定的方式,只會對當前設定的關聯查詢起效,

關聯查詢,一般我們使用association、collection,這兩個元素都有個屬性fetchType,通過這個屬性可以指定關聯查詢的加載方式,

fetchType有兩個值

  • eager:立即加載
  • lazy:延遲加載

下面我們來實作一個需求:還是通過訂單id查詢訂單資訊,并獲取關聯的用戶資訊、訂單詳細串列,用戶資訊我們要求立即加載,而訂單詳情我們要求延遲加載,

mapper xml如下

<resultMap id="orderModelMap2" type="com.zhonghu.chat09.demo5.model.OrderModel">
    <id column="id" property="id"/>
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <!--  通過訂單中user_id作為條件,查詢下單人資訊 -->
    <association property="userModel" fetchType="eager" select="com.zhonghu.chat09.demo5.mapper.UserMapper.getById1" column="user_Id"/>
    <!--  通過訂單id作為條件,查詢詳情串列 -->
    <collection property="orderDetailModelList" fetchType="lazy" select="com.zhonghu.chat09.demo5.mapper.OrderDetailMapper.getListByOrderId1" column="id"/>
</resultMap>
<select id="getById2" resultMap="orderModelMap2">
    <![CDATA[
    SELECT
        a.id ,
        a.user_id,
        a.create_time,
        a.up_time
    FROM
        orders a
    WHERE
        a.id = #{value}
    ]]>
</select>

重點注意上面配置中association、collection這2個元素的fetchType屬性,eager表示立即加載,lazy表示延遲加載,

測驗用例

com.zhonghu.chat09.demo5.Demo5Test#getById2
@Test
public void getById2() throws IOException {
    //指定mybatis全域組態檔
    mybatisConfig = "demo5/mybatis-config2.xml";
    this.before();
    OrderModel orderModel = null;
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        orderModel = mapper.getById2(1);
    }
    log.info("-------分割線--------");
    log.info("{}", orderModel.getOrderDetailModelList());
}

運行輸出

36:54.284 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==>  Preparing: SELECT a.id , a.user_id, a.create_time, a.up_time FROM orders a WHERE a.id = ? 
36:54.321 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==> Parameters: 1(Integer)
36:54.385 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ====>  Preparing: SELECT id,name FROM user where id = ? 
36:54.385 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ====> Parameters: 2(Integer)
36:54.387 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - <====      Total: 1
36:54.389 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - <==      Total: 1
36:54.390 [main] INFO  c.j.chat05.demo5.Demo5Test - -------分割線--------
36:54.392 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - ==>  Preparing: SELECT a.id, a.order_id AS orderId, a.goods_id AS goodsId, a.num, a.total_price AS totalPrice FROM order_detail a WHERE a.order_id = ? 
36:54.392 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - ==> Parameters: 1(Integer)
36:54.397 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - <==      Total: 2
36:54.398 [main] INFO  c.j.chat05.demo5.Demo5Test - [OrderDetailModel(id=1, orderId=1, goodsId=1, num=2, totalPrice=16.00), OrderDetailModel(id=2, orderId=1, goodsId=1, num=1, totalPrice=16.00)]

注意輸出中的分割線,可以分析得出,用戶資訊是和訂單資訊一起立即查出來的,而訂單詳情,是在我們呼叫orderModel.getOrderDetailModelList()獲取訂單串列的時候,采取懶加載的,

鑒別器(discriminator)

有時候,一個資料庫查詢可能會回傳多個不同的結果集(但總體上還是有一定的聯系的), 鑒別器(discriminator)元素就是被設計來應對這種情況的,鑒別器的概念很好理解——它很像 Java 語言中的 switch 陳述句,

discriminator標簽常用的兩個屬性如下:

  • column:該屬性用于設定要進行鑒別比較值的列,
  • javaType:該屬性用于指定列的型別,保證使用相同的java型別來比較值,

discriminator標簽可以有1個或多個case標簽,case標簽有一個比較重要的屬性:

  • value:該值為discriminator指定column用來匹配的值,當匹配的時候,結果會走這個case關聯的映射,

我們使用鑒別器實作一個功能:通過訂單id查詢訂單資訊,當傳入的訂單id為1的時候,獲取訂單資訊及下單人資訊;當傳入的訂單id為2的時候,獲取訂單資訊、下單人資訊、訂單明細資訊;其他情況默認只查詢訂單資訊,

OrderMapper.xml

<resultMap id="orderModelMap1" type="com.zhonghu.chat09.demo6.model.OrderModel">
    <id column="id" property="id"/>
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <!-- 鑒別器 -->
    <discriminator javaType="int" column="id">
        <case value="https://www.cnblogs.com/javazhonghu/p/1">
            <!--通過用戶id查詢用戶資訊-->
            <association property="userModel" select="com.zhonghu.chat09.demo6.mapper.UserMapper.getById1" column="user_Id"/>
        </case>
        <case value="https://www.cnblogs.com/javazhonghu/p/2">
            <!--通過用戶id查詢用戶資訊-->
            <association property="userModel" select="com.zhonghu.chat09.demo6.mapper.UserMapper.getById1" column="user_Id"/>
            <!--通過訂單id查詢訂單串列-->
            <collection property="orderDetailModelList" select="com.zhonghu.chat09.demo6.mapper.OrderDetailMapper.getListByOrderId1" column="id"/>
        </case>
    </discriminator>
</resultMap>
<select id="getById1" resultMap="orderModelMap1">
    <![CDATA[
    SELECT
        a.id ,
        a.user_id,
        a.create_time,
        a.up_time
    FROM
        orders a
    WHERE
        a.id = #{value}
    ]]>
</select>

注意上面的discriminator,這部分是關鍵,discriminator內部的case會和每行查詢結果中的id欄位進行匹配,匹配成功了case內部的關聯查詢會被執行,未匹配上的,只會走discriminator外部默認配置的映射映射規則,

UserMapper.xml

<!-- 通過用戶id查詢用戶資訊 -->
<select id="getById1" resultType="com.zhonghu.chat09.demo6.model.UserModel">
    <![CDATA[
    SELECT id,name FROM user where id = #{user_id}
    ]]>
</select>

OrderDetailMapper.xml

<!-- 通過訂單id查詢訂單明細串列 -->
<select id="getListByOrderId1" resultType="com.zhonghu.chat09.demo6.model.OrderDetailModel">
    <![CDATA[
    SELECT
        a.id,
        a.order_id AS orderId,
        a.goods_id AS goodsId,
        a.num,
        a.total_price AS totalPrice
    FROM
        order_detail a
    WHERE
        a.order_id = #{order_id}
    ]]>
</select>

對應的3個Model類

@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class OrderModel {
    private Integer id;
    private Integer userId;
    private Long createTime;
    private Long upTime;
    //用戶資訊
    private UserModel userModel;
    //訂單詳情串列
    private List<OrderDetailModel> orderDetailModelList;
}

@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class UserModel {
    private Integer id;
    private String name;
}

@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class OrderDetailModel {
    private Integer id;
    private Integer orderId;
    private Integer goodsId;
    private Integer num;
    private Double totalPrice;
}

測驗用例

com.zhonghu.chat09.demo6.Demo6Test#getById1
@Test
public void getById1() throws IOException {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        //查詢訂單為1的
        OrderModel orderModel = mapper.getById1(1);
        log.info("{}", orderModel);
        log.info("------------------------------------------------------------");
        //查詢訂單為2的
        orderModel = mapper.getById1(2);
        log.info("{}", orderModel);
        log.info("------------------------------------------------------------");
        //查詢訂單為3的
        orderModel = mapper.getById1(3);
        log.info("{}", orderModel);
    }
}

運行輸出

58:16.413 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==>  Preparing: SELECT a.id , a.user_id, a.create_time, a.up_time FROM orders a WHERE a.id = ? 
58:16.457 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==> Parameters: 1(Integer)
58:16.481 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ====>  Preparing: SELECT id,name FROM user where id = ? 
58:16.481 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ====> Parameters: 2(Integer)
58:16.488 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - <====      Total: 1
58:16.489 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - <==      Total: 1
58:16.489 [main] INFO  c.j.chat05.demo6.Demo6Test - OrderModel(id=1, userId=2, createTime=1610803573, upTime=1610803573, userModel=UserModel(id=2, name=Java冢狐), orderDetailModelList=null)
58:16.491 [main] INFO  c.j.chat05.demo6.Demo6Test - ------------------------------------------------------------
58:16.491 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==>  Preparing: SELECT a.id , a.user_id, a.create_time, a.up_time FROM orders a WHERE a.id = ? 
58:16.492 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==> Parameters: 2(Integer)
58:16.493 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ====>  Preparing: SELECT id,name FROM user where id = ? 
58:16.493 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ====> Parameters: 1(Integer)
58:16.494 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - <====      Total: 1
58:16.495 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - ====>  Preparing: SELECT a.id, a.order_id AS orderId, a.goods_id AS goodsId, a.num, a.total_price AS totalPrice FROM order_detail a WHERE a.order_id = ? 
58:16.495 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - ====> Parameters: 2(Integer)
58:16.505 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - <====      Total: 1
58:16.505 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - <==      Total: 1
58:16.506 [main] INFO  c.j.chat05.demo6.Demo6Test - OrderModel(id=2, userId=1, createTime=1610803573, upTime=1610803573, userModel=UserModel(id=1, name=冢狐), orderDetailModelList=[OrderDetailModel(id=3, orderId=2, goodsId=1, num=1, totalPrice=8.00)])
58:16.506 [main] INFO  c.j.chat05.demo6.Demo6Test - ------------------------------------------------------------
58:16.506 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==>  Preparing: SELECT a.id , a.user_id, a.create_time, a.up_time FROM orders a WHERE a.id = ? 
58:16.506 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - ==> Parameters: 3(Integer)
58:16.508 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById1 - <==      Total: 1
58:16.509 [main] INFO  c.j.chat05.demo6.Demo6Test - OrderModel(id=3, userId=1, createTime=1610803573, upTime=1610803573, userModel=null, orderDetailModelList=null)

輸出中可以看出,訂單1查詢了2次,訂單2查詢了3次,訂單3查詢了1次;鑒別器算是一個不錯的功能,

繼承(extends)

繼承在java是三大特性之一,可以起到重用代碼的作用,而mybatis也有繼承的功能,和java中的繼承的作用類似,主要在resultMap中使用,可以重用其他resultMap中配置的映射關系,

用法

<resultMap extends="被繼承的resultMap的id"></resultMap>

案例

下面我們使用繼承來對上面的鑒別器的案例改造一下,優化一下代碼

OrderMapper.xml
<resultMap id="orderModelMap2" type="com.zhonghu.chat09.demo6.model.OrderModel">
    <id column="id" property="id"/>
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <!-- 鑒別器 -->
    <discriminator javaType="int" column="id">
        <case value="https://www.cnblogs.com/javazhonghu/p/1" resultMap="orderModelMap3" />
        <case value="https://www.cnblogs.com/javazhonghu/p/2" resultMap="orderModelMap4" />
    </discriminator>
</resultMap>
<resultMap id="orderModelMap3" type="com.zhonghu.chat09.demo6.model.OrderModel" extends="orderModelMap2">
    <!--通過用戶id查詢用戶資訊-->
    <association property="userModel" select="com.zhonghu.chat09.demo6.mapper.UserMapper.getById1" column="user_Id"/>
</resultMap>
<resultMap id="orderModelMap4" type="com.zhonghu.chat09.demo6.model.OrderModel" extends="orderModelMap3">
    <!--通過訂單id查詢訂單串列-->
    <collection property="orderDetailModelList" select="com.zhonghu.chat09.demo6.mapper.OrderDetailMapper.getListByOrderId1" column="id"/>
</resultMap>
<select id="getById2" resultMap="orderModelMap2">
    <![CDATA[
    SELECT
        a.id ,
        a.user_id,
        a.create_time,
        a.up_time
    FROM
        orders a
    WHERE
        a.id = #{value}
    ]]>
</select>

重點在于上面兩個extends屬性,上面orderModelMap3繼承了orderModelMap2中配置的映射關系(除鑒別器之外),自己又加入了一個association去查詢用戶資訊;orderModelMap4繼承了orderModelMap3,自己又加入了一個查詢訂單串列的collection元素,上面使用extends做到了代碼重用,其實和下面這塊代碼寫法效果一樣:

<resultMap id="orderModelMap2" type="com.zhonghu.chat09.demo6.model.OrderModel">
    <id column="id" property="id"/>
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <!-- 鑒別器 -->
    <discriminator javaType="int" column="id">
        <case value="https://www.cnblogs.com/javazhonghu/p/1" resultMap="orderModelMap3" />
        <case value="https://www.cnblogs.com/javazhonghu/p/2" resultMap="orderModelMap4" />
    </discriminator>
</resultMap>
<resultMap id="orderModelMap3" type="com.zhonghu.chat09.demo6.model.OrderModel">
    <id column="id" property="id"/>
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <!--通過用戶id查詢用戶資訊-->
    <association property="userModel" select="com.zhonghu.chat09.demo6.mapper.UserMapper.getById1" column="user_Id"/>
</resultMap>
<resultMap id="orderModelMap4" type="com.zhonghu.chat09.demo6.model.OrderModel">
    <id column="id" property="id"/>
    <result column="user_id" property="userId"/>
    <result column="create_time" property="createTime"/>
    <result column="up_time" property="upTime"/>
    <!--通過用戶id查詢用戶資訊-->
    <association property="userModel" select="com.zhonghu.chat09.demo6.mapper.UserMapper.getById1" column="user_Id"/>
    <!--通過訂單id查詢訂單串列-->
    <collection property="orderDetailModelList" select="com.zhonghu.chat09.demo6.mapper.OrderDetailMapper.getListByOrderId1" column="id"/>
</resultMap>
<select id="getById2" resultMap="orderModelMap2">
    <![CDATA[
    SELECT
        a.id ,
        a.user_id,
        a.create_time,
        a.up_time
    FROM
        orders a
    WHERE
        a.id = #{value}
    ]]>
</select>

測驗用例
com.zhonghu.chat09.demo6.Demo6Test#getById2
@Test
public void getById2() throws IOException {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        //查詢訂單為1的
        OrderModel orderModel = mapper.getById2(1);
        log.info("{}", orderModel);
        log.info("------------------------------------------------------------");
        //查詢訂單為2的
        orderModel = mapper.getById2(2);
        log.info("{}", orderModel);
        log.info("------------------------------------------------------------");
        //查詢訂單為3的
        orderModel = mapper.getById2(3);
        log.info("{}", orderModel);
    }
}

運行輸出
39:55.936 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==>  Preparing: SELECT a.id , a.user_id, a.create_time, a.up_time FROM orders a WHERE a.id = ? 
39:55.969 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==> Parameters: 1(Integer)
39:55.986 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ====>  Preparing: SELECT id,name FROM user where id = ? 
39:55.987 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ====> Parameters: 2(Integer)
39:55.992 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - <====      Total: 1
39:55.993 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - <==      Total: 1
39:55.993 [main] INFO  c.j.chat05.demo6.Demo6Test - OrderModel(id=1, userId=2, createTime=1610803573, upTime=1610803573, userModel=UserModel(id=2, name=Java冢狐), orderDetailModelList=null)
39:55.994 [main] INFO  c.j.chat05.demo6.Demo6Test - ------------------------------------------------------------
39:55.994 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==>  Preparing: SELECT a.id , a.user_id, a.create_time, a.up_time FROM orders a WHERE a.id = ? 
39:55.995 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==> Parameters: 2(Integer)
39:55.995 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - ====>  Preparing: SELECT a.id, a.order_id AS orderId, a.goods_id AS goodsId, a.num, a.total_price AS totalPrice FROM order_detail a WHERE a.order_id = ? 
39:55.996 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - ====> Parameters: 2(Integer)
39:56.000 [main] DEBUG c.j.c.d.m.O.getListByOrderId1 - <====      Total: 1
39:56.001 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ====>  Preparing: SELECT id,name FROM user where id = ? 
39:56.004 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - ====> Parameters: 1(Integer)
39:56.005 [main] DEBUG c.j.c.d.mapper.UserMapper.getById1 - <====      Total: 1
39:56.005 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - <==      Total: 1
39:56.005 [main] INFO  c.j.chat05.demo6.Demo6Test - OrderModel(id=2, userId=1, createTime=1610803573, upTime=1610803573, userModel=UserModel(id=1, name=冢狐), orderDetailModelList=[OrderDetailModel(id=3, orderId=2, goodsId=1, num=1, totalPrice=8.00)])
39:56.005 [main] INFO  c.j.chat05.demo6.Demo6Test - ------------------------------------------------------------
39:56.005 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==>  Preparing: SELECT a.id , a.user_id, a.create_time, a.up_time FROM orders a WHERE a.id = ? 
39:56.006 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - ==> Parameters: 3(Integer)
39:56.007 [main] DEBUG c.j.c.d.mapper.OrderMapper.getById2 - <==      Total: 1
39:56.007 [main] INFO  c.j.chat05.demo6.Demo6Test - OrderModel(id=3, userId=1, createTime=1610803573, upTime=1610803573, userModel=null, orderDetailModelList=null)

總結

本篇開篇重點介紹了有關MyBatis的延遲加載的相關的內容,對其中的全域延遲加載和部分延遲加載進行了注重的介紹,介紹完延遲加載后,又介紹了一些與之相關的鑒別器和繼承的相關內容,

最后

  • 如果覺得看完有識訓,希望能關注一下,順便給我點個贊,這將會是我更新的最大動力,感謝各位的支持
  • 歡迎各位關注我的公眾號【java冢狐】,專注于java和計算機基礎知識,保證讓你看完有所識訓,不信你打我
  • 求一鍵三連:點贊、轉發、在看,
  • 如果看完有不同的意見或者建議,歡迎多多評論一起交流,感謝各位的支持以及厚愛,

——我是冢狐,和你一樣熱愛編程,

歡迎關注公眾號“Java冢狐”獲取最新訊息

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/262783.html

標籤:Java

上一篇:死磕Spring之IoC篇 - BeanDefinition 的加載階段(XML 檔案)

下一篇:hashMap原始碼學習

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more