最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文了解mybatis的延遲加載

 更新時(shí)間:2022年07月15日 09:11:08   作者:默念x  
本文主要為大家詳細(xì)介紹下mybatis的延遲加載,從原理上介紹下怎么使用、有什么好處能規(guī)避什么問題。感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

本文主要介紹下mybatis的延遲加載,從原理上介紹下怎么使用、有什么好處能規(guī)避什么問題。延遲加載一般用于級(jí)聯(lián)查詢(級(jí)聯(lián)查詢可以將主表不能直接查詢的數(shù)據(jù)使用自定義映射規(guī)則調(diào)用字表來(lái)查,主查詢查完之后通過某個(gè)column列或多個(gè)列將查詢結(jié)果傳遞給子查詢,子查詢?cè)俑鶕?jù)主查詢傳遞的參數(shù)進(jìn)行查詢,最后將子查詢結(jié)果進(jìn)行映射)。mybatis的懶加載是通過創(chuàng)建代理對(duì)象來(lái)實(shí)現(xiàn)的,只有當(dāng)調(diào)用getter等方法的時(shí)候才會(huì)去查詢子查詢,查詢后完成設(shè)值再獲取值。

1. 什么時(shí)候會(huì)創(chuàng)建代理對(duì)象

  private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
    this.useConstructorMappings = false; // reset previous mapping result
    final List<Class<?>> constructorArgTypes = new ArrayList<>();
    final List<Object> constructorArgs = new ArrayList<>();
    // 創(chuàng)建result接收對(duì)象
    Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
    if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
      // 處理其他屬性properties
      final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
      for (ResultMapping propertyMapping : propertyMappings) {
        // issue gcode #109 && issue #149 創(chuàng)建代理
        if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
          resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
          break;
        }
      }
    }
    // 使用有參構(gòu)造函數(shù)創(chuàng)建了對(duì)象
    this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result
    return resultObject;
  }

通過mybatis代碼propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()發(fā)現(xiàn)只有當(dāng)存在嵌套查詢select子句和isLazy=true的時(shí)候才會(huì)創(chuàng)建代理,那么isLazy=true是什么條件,從創(chuàng)建ResultMapping的代碼中可以看到boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));只有手動(dòng)設(shè)置fetchType=lazy或者全局設(shè)置configuration的lazyLoadingEnabled=true,兩者缺一不可。

關(guān)于代理是通過Javassist創(chuàng)建的,下面有一個(gè)簡(jiǎn)單的例子

public class HelloMethodHandler implements MethodHandler {

  private Object target;

  public HelloMethodHandler(Object o) {
    this.target = o;
  }

  @Override
  public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
    String methodName = thisMethod.getName();
    if (methodName.startsWith("get")) {
      System.out.println("select database....");
      // 進(jìn)行sql查詢到結(jié)果并set設(shè)置值
      ((Student)self).setName("monian");
    }
    return proceed.invoke(self, args);
  }

  public static void main(String[] args) throws Exception {
    Student student = new Student();
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.setSuperclass(Student.class);

    Constructor<Student> declaredConstructor = Student.class.getDeclaredConstructor();
    Object o = proxyFactory.create(declaredConstructor.getParameterTypes(), new Object[]{});
    ((Proxy)o).setHandler(new HelloMethodHandler(student));

    Student proxy = (Student)o;
    System.out.println(proxy.getName());
  }
}

mybatis的原理就是通過創(chuàng)建一個(gè)代理對(duì)象,當(dāng)通過這個(gè)代理對(duì)象調(diào)用getter、is、equals、clone、toString、hashCode等方法時(shí)會(huì)調(diào)用select子查詢,然后完成設(shè)置,最后取值就像早就獲取到一樣。

2. 如何使用

public class UserDO {

  private Integer userId;

  private String username;

  private String password;

  private String nickname;

  private List<PermitDO> permitDOList;

  public UserDO() {}
}
<resultMap id="BaseMap" type="org.apache.ibatis.study.entity.UserDO">
    <id column="user_id" jdbcType="INTEGER" property="userId" />
    <result column="username" jdbcType="VARCHAR" property="username" />
    <result column="password" jdbcType="VARCHAR" property="password" />
    <result column="nickname" jdbcType="VARCHAR" property="nickname"/>

    <collection property="permitDOList" column="user_id" select="getPermitsByUserId"
     fetchType="lazy">

    </collection>
</resultMap>

  <resultMap id="PermitBaseMap" type="org.apache.ibatis.study.entity.PermitDO">
    <id column="id" jdbcType="INTEGER" property="id"/>
    <result column="code" jdbcType="VARCHAR" property="code"/>
    <result column="name" jdbcType="VARCHAR" property="name"/>
    <result column="type" jdbcType="TINYINT" property="type"/>
    <result column="pid" jdbcType="INTEGER" property="pid"/>
  </resultMap>
  
      
   <select id="getByUserId2" resultMap="BaseMap">
    select * from user
    where user_id = #{userId}
  </select>

  <select id="getPermitsByUserId" resultMap="PermitBaseMap">
    select p.*
    from user_permit up
    inner join permit p on up.permit_id = p.id
    where up.user_id = #{userId}
  </select>

通過fetchType=lazy指定子查詢getPermitsByUserId使用懶加載,這樣的話就不用管全局配置lazyLoadingEnabled是true還是false了。當(dāng)然這里可以直接用多表關(guān)聯(lián)查詢不使用子查詢,使用方法在上一篇文章

測(cè)試代碼

public class Test {

  public static void main(String[] args) throws IOException {

    try (InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml")) {
      // 構(gòu)建session工廠 DefaultSqlSessionFactory
      SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
      SqlSession sqlSession = sqlSessionFactory.openSession();
      UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
      UserDO userDO = userMapper.getByUserId2(1);
      System.out.println(userDO);
    }
  }

}

結(jié)果如下,打了斷點(diǎn)可以看到原userDO對(duì)象已被代理并且permitDOList是null需要調(diào)用get方法才會(huì)去查詢拿到值,咳咳這邊之前直接運(yùn)行顯示是已經(jīng)把permitDOList查詢出來(lái)了,想了半天啥原因后來(lái)才發(fā)現(xiàn)println會(huì)調(diào)用userDO對(duì)象的toString方法,而toString方法也會(huì)走代理方法直接去調(diào)用子查詢的

3.延遲加載的好處

延遲加載主要能解決mybatis的N+1問題,什么是N+1問題其實(shí)叫1+N更為合理,以上面的業(yè)務(wù)例子來(lái)說就是假設(shè)一次查詢出來(lái)10000個(gè)用戶,那么還需要針對(duì)這10000個(gè)用戶使用子查詢getPermitsByUserId獲取每個(gè)用戶的權(quán)限列表,需要10000次查詢,總共10001次,真實(shí)情況下你可能并不需要每個(gè)子查詢的結(jié)果,這樣就浪費(fèi)數(shù)據(jù)庫(kù)連接資源了。如果使用延遲加載的話就相當(dāng)于不用進(jìn)行這10000次查詢,因?yàn)樗堑鹊侥阏嬲褂玫臅r(shí)候才會(huì)調(diào)用子查詢獲取結(jié)果。

以上就是一文了解mybatis的延遲加載的詳細(xì)內(nèi)容,更多關(guān)于mybatis延遲加載的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java編程中10個(gè)最佳的異常處理技巧

    Java編程中10個(gè)最佳的異常處理技巧

    這篇文章主要介紹了Java編程中10個(gè)最佳的異常處理技巧,在本文中,將討論Java異常處理最佳實(shí)踐,這些Java最佳實(shí)踐遵循標(biāo)準(zhǔn)的JDK庫(kù),和幾個(gè)處理錯(cuò)誤和異常的開源代碼,這還是一個(gè)提供給java程序員編寫健壯代碼的便利手冊(cè),需要的朋友可以參考下
    2015-01-01
  • java實(shí)現(xiàn)簡(jiǎn)單的五子棋游戲

    java實(shí)現(xiàn)簡(jiǎn)單的五子棋游戲

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單的五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • java刪除數(shù)組中的某一個(gè)元素的方法

    java刪除數(shù)組中的某一個(gè)元素的方法

    下面小編就為大家?guī)?lái)一篇java刪除數(shù)組中的某一個(gè)元素的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧
    2017-01-01
  • 詳解如何在Java中加密和解密zip文件

    詳解如何在Java中加密和解密zip文件

    在本文中,我們來(lái)學(xué)習(xí)如何用Zip4j庫(kù)創(chuàng)建受密碼保護(hù)的壓縮文件并將其解壓,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下
    2022-09-09
  • java線程之用Thread類創(chuàng)建線程的方法

    java線程之用Thread類創(chuàng)建線程的方法

    本篇文章介紹了,Thread類創(chuàng)建線程的方法。需要的朋友參考下
    2013-05-05
  • Java Swing 非常漂亮外觀Nimbus的使用方法實(shí)例

    Java Swing 非常漂亮外觀Nimbus的使用方法實(shí)例

    Java Swing 非常漂亮外觀Nimbus的使用方法實(shí)例,需要的朋友可以參考一下
    2013-02-02
  • Java Character類的詳解

    Java Character類的詳解

    本篇文章主要詳細(xì)介紹了JAVA中 Character類 方法等,需要的朋友可以參考下
    2017-04-04
  • CentOS 7系統(tǒng)下配置自定義JDK的教程

    CentOS 7系統(tǒng)下配置自定義JDK的教程

    這篇文章主要給大家介紹了在CentOS 7系統(tǒng)下配置自定義JDK的教程,文中將配置的方法教程介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-06-06
  • Java使用MulticastSocket實(shí)現(xiàn)群聊應(yīng)用程序

    Java使用MulticastSocket實(shí)現(xiàn)群聊應(yīng)用程序

    這篇文章主要為大家詳細(xì)介紹了Java使用MulticastSocket實(shí)現(xiàn)群聊應(yīng)用程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • java并發(fā)之synchronized

    java并發(fā)之synchronized

    這篇文章主要介紹了java并發(fā)關(guān)鍵字synchronized,包括內(nèi)容synchronized的使用、synchronized背后的Monitor、synchronized保證可見性和防重排序、使用synchronized注意嵌套鎖定,具體內(nèi)容請(qǐng)看下面文章吧
    2021-10-10

最新評(píng)論

南昌县| 荆州市| 于田县| 鹤壁市| 渑池县| 宜章县| 马尔康县| 长汀县| 麻江县| 拉孜县| 皋兰县| 清河县| 庆安县| 紫阳县| 镇宁| 毕节市| 铜川市| 新野县| 宁乡县| 南汇区| 望谟县| 新疆| 铜川市| 方山县| 汶川县| 格尔木市| 富源县| 荔波县| 芷江| 巴东县| 高雄县| 梁山县| 蓬安县| 广灵县| 淮北市| 独山县| 溆浦县| 高要市| 九江市| 海淀区| 民勤县|