8. Mybatis延遲加載策略

Mybatis 中一對一项栏,一對多亡资,多對多關(guān)系的配置及實現(xiàn),可以實現(xiàn)對象的關(guān)聯(lián)查詢板驳。實際開發(fā)過程中很多時候我們并不需要總是在加載用戶信息時就一定要加載他的賬戶信息。此時就是我們所說的延遲加載碍拆。

1. 何為延遲加載

延遲加載:
就是在需要用到數(shù)據(jù)時才進行加載若治,不需要用到數(shù)據(jù)時就不加載數(shù)據(jù)。延遲加載也稱懶加載.

好處:先從單表查詢感混,需要時再從關(guān)聯(lián)表去關(guān)聯(lián)查詢端幼,大大提高數(shù)據(jù)庫性能,因為查詢單表要比關(guān)聯(lián)查詢多張表速度要快弧满。

壞處 :因為只有當(dāng)需要用到數(shù)據(jù)時婆跑,才會進行數(shù)據(jù)庫查詢,這樣在大批量數(shù)據(jù)查詢時庭呜,因為查詢工作也要消耗時間滑进,所以可能造成用戶等待時間變長摹迷,造成用戶體驗下降。

延遲加載:在真正使用數(shù)據(jù)時才發(fā)起查詢郊供,不用的時候不查詢峡碉。按需加載(懶加載)
立即加載:不管用不用,只要一調(diào)用方法驮审,馬上發(fā)起查詢鲫寄。

在對應(yīng)的四種表關(guān)系中:一對多,多對一疯淫,一對一地来,多對多
1)一對多,多對多:通常情況下我們都是采用延遲加載熙掺。
2)多對一未斑,一對一:通常情況下我們都是采用立即加載。

2. 實現(xiàn)需求

需求:
查詢賬戶(Account)信息并且關(guān)聯(lián)查詢用戶(User)信息币绩。如果先查詢賬戶(Account)信息即可滿足要求蜡秽,當(dāng)我們需要查詢用戶(User)信息時再查詢用戶(User)信息。把對用戶(User)信息的按需去查詢就是延遲加
載缆镣。
mybatis實現(xiàn)多表操作時芽突,我們使用了resultMap來實現(xiàn)一對一,一對多董瞻,多對多關(guān)系的操作寞蚌。主要是通過 association、collection 實現(xiàn)一對一及一對多映射钠糊。association挟秤、collection 具備延遲加載功能。

3. 使用 assocation實現(xiàn)延遲加載

需求:查詢賬戶信息同時查詢用戶信息抄伍。

3.1 創(chuàng)建工程
image.png

這里可以用之前的一對多的工程模板為例艘刚,修改如下


image.png
3.2 賬戶的持久層 DAO
package com.neuedu.dao;

import com.neuedu.domain.Account;

import java.util.List;

public interface AccountDao {

    /**
     * 查詢所有賬戶,同時還要獲取到當(dāng)前賬戶的所屬用戶信息
     * @return
     */
    List<Account> findAll();

}

3.3 用戶的持久層 映射文件

UserDao.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.neuedu.dao.UserDao">

    <!-- 定義User的resultMap-->
    <resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <!-- 配置user對象中accounts集合的映射 -->
        <collection property="accounts" ofType="account">
            <id column="aid" property="id"></id>
            <result column="uid" property="uid"></result>
            <result column="money" property="money"></result>
        </collection>
    </resultMap>

    <!-- 查詢所有 -->
    <select id="findAll" resultMap="userAccountMap">
        select * from user 
    </select>

    <!-- 根據(jù)id查詢用戶 -->
    <select id="findById" parameterType="INT" resultType="user">
        select * from user where id = #{uid}
    </select>

</mapper>
3.4 賬戶的持久層 接口和 映射文件

AccountDao.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.neuedu.dao.AccountDao">

    <!-- 定義封裝account和user的resultMap -->
    <resultMap id="accountUserMap" type="account">
        <id property="id" column="id"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!-- 一對一的關(guān)系映射:配置封裝user的內(nèi)容
        select屬性指定的內(nèi)容:查詢用戶的唯一標(biāo)識:
        column屬性指定的內(nèi)容:用戶根據(jù)id查詢時逝慧,所需要的參數(shù)的值
        -->
        <association property="user" column="uid" javaType="user" select="com.neuedu.dao.UserDao.findById"></association>
    </resultMap>

    <!-- 查詢所有 -->
    <select id="findAll" resultMap="accountUserMap">
        select * from account
    </select>

    <!-- 根據(jù)用戶id查詢賬戶列表 -->
    <select id="findAccountByUid" resultType="account">
        select * from account where uid = #{uid}
    </select>
    
</mapper>

3.5 測試類

package com.neuedu.test;

import com.neuedu.dao.AccountDao;
import com.neuedu.domain.Account;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

public class AccountTest {

    private InputStream in;
    private SqlSession sqlSession;
    private AccountDao accountDao;

    @Before//用于在測試方法執(zhí)行之前執(zhí)行
    public void init()throws Exception{
        //1.讀取配置文件昔脯,生成字節(jié)輸入流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.獲取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //3.獲取SqlSession對象
        sqlSession = factory.openSession(true);
        //4.獲取dao的代理對象
        accountDao = sqlSession.getMapper(AccountDao.class);
    }

    @After//用于在測試方法執(zhí)行之后執(zhí)行
    public void destroy()throws Exception{
        //提交事務(wù)
        // sqlSession.commit();
        //6.釋放資源
        sqlSession.close();
        in.close();
    }

    /**
     * 測試查詢所有
     */
    @Test
    public void testFindAll(){
        List<Account> accounts = accountDao.findAll();
        for(Account account : accounts){
            System.out.println("--------每個account的信息------------");
            System.out.println(account);
            System.out.println(account.getUser());
        }
    }


}

3.6 開啟 Mybatis 的延遲加載策略

image.png

未開啟延遲加載

image.png

image.png
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 配置properties-->
    <properties resource="jdbcConfig.properties"></properties>

    <!--配置參數(shù)-->
    <settings>
        <!--開啟Mybatis支持延遲加載-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"></setting>
    </settings>

    <!--使用typeAliases配置別名啄糙,它只能配置domain中類的別名 -->
    <typeAliases>
        <package name="com.neuedu.domain"></package>
    </typeAliases>

    <!--配置環(huán)境-->
    <environments default="mysql">
        <!-- 配置mysql的環(huán)境-->
        <environment id="mysql">
            <!-- 配置事務(wù) -->
            <transactionManager type="JDBC"></transactionManager>

            <!--配置連接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </dataSource>
        </environment>
    </environments>
    <!-- 配置映射文件的位置 -->
    <mappers>
        <package name="com.neuedu.dao"></package>
    </mappers>
</configuration>
image.png

4. 使用 Collection 實現(xiàn)延遲加載

同樣我們也可以在一對多關(guān)系配置的<collection>結(jié)點中配置延遲加載策略笛臣。
<collection>結(jié)點中也有 select 屬性,column 屬性隧饼。
需求:
完成加載用戶對象時沈堡,查詢該用戶所擁有的賬戶信息。

4.1 在 在 User 實體類中加入 List<Account> 屬性
public class User implements Serializable {

    private Integer id;
    private String username;
    private String address;
    private String sex;
    private Date birthday;

    //一對多關(guān)系映射:主表實體應(yīng)該包含從表實體的集合引用
    private List<Account> accounts;

    public List<Account> getAccounts() {
        return accounts;
    }

    public void setAccounts(List<Account> accounts) {
        this.accounts = accounts;
    }

...
}

4.2 編寫用戶和賬戶持久層接口的方法
public interface AccountDao {

    /**
     * 根據(jù)用戶id查詢賬戶信息
     * @param uid
     * @return
     */
    List<Account> findAccountByUid(Integer uid);

}
4.3 編寫用戶持久層映射 配置

UserDao.xml

<resultMap type="user" id="userMap">
    <id column="id" property="id"></id>
    <result column="username" property="username"/>
    <result column="address" property="address"/>
    <result column="sex" property="sex"/>
    <result column="birthday" property="birthday"/>
    <!-- collection 是用于建立一對多中集合屬性的對應(yīng)關(guān)系
    ofType 用于指定集合元素的數(shù)據(jù)類型
    select 是用于指定查詢賬戶的唯一標(biāo)識(賬戶的 dao 全限定類名加上方法名稱)
    column 是用于指定使用哪個字段的值作為條件查詢
-->
    <collection property="accounts" ofType="account"
    select="com.neuedu.dao.AccountDao.findByUid"
    column="id">
    </collection>
</resultMap>
<!-- 配置查詢所有操作 -->
<select id="findAll" resultMap="userMap">
    select * from user
</select>

<collection> 標(biāo)簽 :
主要用于加載關(guān)聯(lián)的集合對象

select 屬性 :用于指定查詢 account 列表的 sql 語句燕雁,所以填寫的是該 sql 映射的 id

column 屬性 :用于指定 select 屬性的 sql 語句的參數(shù)來源诞丽,上面的參數(shù)來自于 user 的 id 列鲸拥,所以就寫成 id 這一個字段名了

4.4 編寫賬戶持久層映射配置
<!-- 根據(jù)用戶 id 查詢賬戶信息 -->
<select id="findByUid" resultType="account" parameterType="int">
select * from account where uid = #{uid}
</select>
4.5 測試只加載用戶信息
image.png

我們發(fā)現(xiàn)并沒有加載 Account 賬戶信息。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末僧免,一起剝皮案震驚了整個濱河市刑赶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌懂衩,老刑警劉巖撞叨,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異浊洞,居然都是意外死亡牵敷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門法希,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枷餐,“玉大人,你說我怎么就攤上這事苫亦∶撸” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵屋剑,是天一觀的道長村生。 經(jīng)常有香客問我,道長饼丘,這世上最難降的妖魔是什么趁桃? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮肄鸽,結(jié)果婚禮上卫病,老公的妹妹穿的比我還像新娘。我一直安慰自己典徘,他們只是感情好蟀苛,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逮诲,像睡著了一般帜平。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上梅鹦,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天裆甩,我揣著相機與錄音,去河邊找鬼齐唆。 笑死嗤栓,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茉帅,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼叨叙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了堪澎?” 一聲冷哼從身側(cè)響起擂错,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎樱蛤,沒想到半個月后马昙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡刹悴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年行楞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片土匀。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡子房,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出就轧,到底是詐尸還是另有隱情证杭,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布妒御,位于F島的核電站解愤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏乎莉。R本人自食惡果不足惜送讲,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望惋啃。 院中可真熱鬧哼鬓,春花似錦、人聲如沸边灭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绒瘦。三九已至称簿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惰帽,已是汗流浹背憨降。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留善茎,地道東北人券册。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像垂涯,于是被迫代替她去往敵國和親烁焙。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容