自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MyBatis的延遲加載,你知道是怎么實(shí)現(xiàn)的么?

數(shù)據(jù)庫(kù) 其他數(shù)據(jù)庫(kù)
延遲加載也稱為懶加載、惰性加載,使用延遲加載可以提高程序的運(yùn)行效率,針對(duì)數(shù)據(jù)持久層的操作,在某些特定查詢的情況下去訪問(wèn)特定的數(shù)據(jù)庫(kù),在其他情況下可以不訪問(wèn)某些數(shù)據(jù)表,盡量減少 SQL 的執(zhí)行,從而達(dá)到提高速度的目的,是對(duì)數(shù)據(jù)庫(kù)操作的一種優(yōu)化。

今天了不起來(lái)說(shuō)說(shuō)這個(gè)關(guān)于 Mybatis ,為什么要說(shuō) Mybatis 呢?因?yàn)楝F(xiàn)在面試的時(shí)候,除了那些最基礎(chǔ)的,比如如何防止 SQL 注入,以及 Mybatis 的一級(jí)緩存,二級(jí)緩存之后,還有一些其他的問(wèn)題,比如 Mybatis 的延遲加載,并且需要說(shuō)一下延遲加載的使用場(chǎng)景。今天了不起就來(lái)給大家說(shuō)一下這個(gè)延遲加載到底是怎么回事,以及延遲加載的使用場(chǎng)景。

什么是延遲加載?

延遲加載也稱為懶加載、惰性加載,使用延遲加載可以提高程序的運(yùn)行效率,針對(duì)數(shù)據(jù)持久層的操作,在某些特定查詢的情況下去訪問(wèn)特定的數(shù)據(jù)庫(kù),在其他情況下可以不訪問(wèn)某些數(shù)據(jù)表,盡量減少 SQL 的執(zhí)行,從而達(dá)到提高速度的目的,是對(duì)數(shù)據(jù)庫(kù)操作的一種優(yōu)化。

什么情況下會(huì)出現(xiàn)延遲加載的情況

我們來(lái)舉個(gè)簡(jiǎn)單的例子

在一對(duì)多中,當(dāng)我們有一個(gè)用戶,它有個(gè)100個(gè)訂單 在查詢用戶的時(shí)候,要不要把關(guān)聯(lián)的訂單查出來(lái)? 在查詢訂單的時(shí)候,要不要把關(guān)聯(lián)的用戶查出來(lái)?

那這個(gè)時(shí)候,答案就很清晰了,肯定要查出來(lái)的,但是,是我在需要的地方。

在查詢用戶時(shí),用戶下的訂單應(yīng)該是,什么時(shí)候用,什么時(shí)候查詢。

在查詢訂單時(shí),訂單所屬的用戶信息應(yīng)該是隨著訂單一起查詢出來(lái)

這個(gè)時(shí)候我們就會(huì)用到延遲加載了,我用的時(shí)候,我們就查詢,我們不用的時(shí)候,我們就不再繼續(xù)的進(jìn)行查詢了。

注意:延遲加載的應(yīng)用要求:關(guān)聯(lián)對(duì)象的查詢與主加載對(duì)象的查詢必須是分別進(jìn)行的select語(yǔ)句,不能是使用多表連接所進(jìn)行的select查詢。

延遲加載分類

其實(shí)延遲加載也是有區(qū)分對(duì)的,而這個(gè)區(qū)分就是,全局的延遲加載和局部的延遲加載。

全局延遲加載

全局延遲加載的實(shí)現(xiàn),實(shí)際上是通過(guò)修改配置文件來(lái)進(jìn)行實(shí)現(xiàn)的,只要改了對(duì)應(yīng)的配置配置文件,重啟之后,肯定直接全局實(shí)現(xiàn),所有需要用到全局加載的 xml 文件,都可以進(jìn)行實(shí)現(xiàn)了。

修改內(nèi)容如下:

<settings>
    <!--開(kāi)啟全局延遲加載功能-->
    <setting name="lazyLoadingEnabled" value="true"/>
</settings>

局部延遲加載

在association和collection標(biāo)簽中都有?個(gè)fetchType屬性,通過(guò)修改它的值,可以修改局部的加載策略。

實(shí)現(xiàn)方式如下:

<!-- 開(kāi)啟?對(duì)多 延遲加載 -->
<resultMap id="userMap" type="user">
    <id column="id" property="id"></id>
    <result column="username" property="username"></result>
    <result column="password" property="password"></result>
    <result column="birthday" property="birthday"></result>
<!--
fetchType="lazy" 懶加載策略
fetchType="eager" ?即加載策略
-->
    <collection property="orderList" ofType="order" column="id"
        select="com.lagou.dao.OrderMapper.findByUid" fetchType="lazy">
    </collection>
</resultMap>
<select id="findAll" resultMap="userMap">
    SELECT * FROM `user`
</select>

其實(shí)在這里,我們需要注意一個(gè)內(nèi)容,那就是延遲加載的時(shí)候:局部的加載策略的優(yōu)先級(jí)高于全局的加載策略。

這個(gè)也是面試的時(shí)候,經(jīng)常會(huì)被問(wèn)到的內(nèi)容。

那么我們就得來(lái)看看這個(gè)延遲加載的具體實(shí)現(xiàn):

Spring配置加載

public class Configuration {
        /**
         * aggressiveLazyLoading:
         * 當(dāng)開(kāi)啟時(shí),任何?法的調(diào)?都會(huì)加載該對(duì)象的所有屬性。否則,每個(gè)屬性會(huì)按需加載(參考lazyLoadTriggerMethods).
         * 默認(rèn)為true
         */
        protected boolean aggressiveLazyLoading;
        /**
         * 延遲加載觸發(fā)?法
         */
        protected Set<String> lazyLoadTriggerMethods = new HashSet<String>(Arrays.asList(new String[]{"equals", "clone", "hashCode", "toString" }));
        /**
         * 是否開(kāi)啟延遲加載
         */
        protected boolean lazyLoadingEnabled = false;
 
        /**
         * 默認(rèn)使?Javassist代理??
         *
         * @param proxyFactory
         */
        public void setProxyFactory(ProxyFactory proxyFactory) {
            if (proxyFactory == null) {
                proxyFactory = new JavassistProxyFactory();
            }
            this.proxyFactory = proxyFactory;
        }
        //省略...
    }

Spring的加載,我們已經(jīng)看到了,接下來(lái)我們還得看看延遲加載代理對(duì)象創(chuàng)建,他都是怎么來(lái)創(chuàng)建的,說(shuō)到創(chuàng)建類,那么就得找到這個(gè) ResultSetHandler 這個(gè)類了,內(nèi)部是有有個(gè) handleResultSets 的方法,而方法內(nèi)部,就有加載的過(guò)程。默認(rèn)采用javassistProxy進(jìn)行代理對(duì)象的創(chuàng)建

// 創(chuàng)建映射后的結(jié)果對(duì)象
    private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {
        // useConstructorMappings ,表示是否使用構(gòu)造方法創(chuàng)建該結(jié)果對(duì)象。此處將其重置
        this.useConstructorMappings = false; // reset previous mapping result
        final List<Class<?>> constructorArgTypes = new ArrayList<>(); // 記錄使用的構(gòu)造方法的參數(shù)類型的數(shù)組
        final List<Object> constructorArgs = new ArrayList<>(); // 記錄使用的構(gòu)造方法的參數(shù)值的數(shù)組
        // 創(chuàng)建映射后的結(jié)果對(duì)象
        Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);
        if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
            // 如果有內(nèi)嵌的查詢,并且開(kāi)啟延遲加載,則創(chuàng)建結(jié)果對(duì)象的代理對(duì)象
            final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();
            for (ResultMapping propertyMapping : propertyMappings) {
                // issue gcode #109 && issue #149
                if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {
               // 創(chuàng)建延遲加載代理對(duì)象
                    resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);
                    break;
                }
            }
        }
        // 判斷是否使用構(gòu)造方法創(chuàng)建該結(jié)果對(duì)象
        this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping result
        return resultObject;
    }

如果你想要在你的代碼中驗(yàn)證延遲加載是否生效的話,那么有一個(gè)很簡(jiǎn)單的方法,開(kāi)啟日志的 SQL 打印功能,那么就可以直接驗(yàn)證你的延遲加載是否生效了。

為什么需要延遲加載

其實(shí)這也是延遲加載的優(yōu)點(diǎn),優(yōu)點(diǎn)如下:

先從單表查詢,需要時(shí)再?gòu)年P(guān)聯(lián)表去關(guān)聯(lián)查詢,??提?數(shù)據(jù)庫(kù)性能,因?yàn)椴樵儐伪硪汝P(guān)聯(lián)查詢多張表速度要快。

但是缺點(diǎn)也很明顯:

有當(dāng)需要用到數(shù)據(jù)時(shí),才會(huì)進(jìn)行數(shù)據(jù)庫(kù)查詢,這樣在大批量數(shù)據(jù)查詢時(shí),因?yàn)椴樵児ぷ饕惨臅r(shí)間,所以可能造成?戶等待時(shí)間變長(zhǎng),造成用戶體驗(yàn)下降。

責(zé)任編輯:武曉燕 來(lái)源: Java極客技術(shù)
相關(guān)推薦

2021-01-21 09:09:18

時(shí)區(qū)轉(zhuǎn)換程序

2024-11-26 00:45:29

free區(qū)域字段

2023-08-30 07:27:39

2020-10-16 15:06:59

開(kāi)發(fā)技術(shù)方案

2025-01-21 10:04:40

Java并發(fā)阻塞隊(duì)列

2024-12-04 08:40:19

2013-02-27 10:27:44

GitHub

2024-04-10 10:15:16

監(jiān)聽(tīng)

2024-02-19 00:00:00

Docker輕量級(jí)容器

2020-06-29 18:54:39

大數(shù)據(jù)新發(fā)地疫情

2024-02-22 09:21:09

.NETActionOptions

2010-01-06 15:36:30

Linux操作系統(tǒng)

2017-12-11 15:04:58

404錯(cuò)誤HTTP代碼

2023-10-08 09:42:41

GitHubDataTable?Fill

2022-08-11 17:14:37

Java

2022-12-09 09:46:55

插件Lombok

2021-01-13 10:56:37

MybatisAPIMybatis 架構(gòu)

2012-08-15 11:36:13

Hibernate

2020-12-17 08:56:51

單例模式JVM

2020-12-08 09:25:41

死鎖MySQL數(shù)據(jù)庫(kù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)