一、什么是延遲加載
- 延遲加載:先從單表查詢恬总、需要時再從關(guān)聯(lián)表去關(guān)聯(lián)查詢肚邢,大大提高數(shù)據(jù)庫性能。
-
resultMap
可以實現(xiàn)高級映射(使用association贱纠、collection
實現(xiàn)一對一和一對多映射)谆焊,association浦夷、collection
具備延遲加載的功能辜王。 - 如果現(xiàn)在的需求:
查詢訂單并且關(guān)聯(lián)查詢用戶信息剃执。如果先查詢訂單信息即可滿足要求肾档,當(dāng)我們需要用戶信息時再查詢用戶信息。把對用戶信息的按需查詢就是延遲加載俗慈。
二遣耍、使用association實現(xiàn)延遲加載
需求在上面已經(jīng)給出舵变。(工程mybatis12
)
2.1 mapper.xml
- 1.先只查詢訂單信息
SELECT * FROM orders
在查詢訂單的statement
中使用association
去延遲加載(執(zhí)行)下面的statement
。
- 2.關(guān)聯(lián)查詢用戶信息
通過上面查詢到的訂單信息中的user_id
去關(guān)聯(lián)查詢用戶信息
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
說明:上面的sql
只是說明赊豌,語法是不正確的碘饼。也就是說我們可以通過訂單信息中的user_id
去關(guān)聯(lián)查詢用戶的各項信息悲伶。
OrdersMapper.xml
<!-- 延遲加載的resultMap -->
<resultMap type="Orders" id="OrdersUserLazyResultMap">
<!-- 首先需要對訂單信息進(jìn)行配置 -->
<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"/>
<!-- 對用戶信息進(jìn)行延遲加載
select:指定延遲加載要執(zhí)行的sql語句(statement)麸锉,這里根據(jù)user_id查詢用戶信息的statement,
要使用UserMapper.xml中的findUserById來完成根據(jù)用戶id(user_id)的用戶信息查詢五慈,需要使用命名空間
column: 訂單信息中關(guān)聯(lián)用戶信息查詢的列主穗,是user_id
關(guān)聯(lián)查詢的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="User" select="cn.itcast.mapper.UserMapper.findUserById" column="user_id">
</association>
</resultMap>
<!-- 查詢訂單忽媒,關(guān)聯(lián)查詢用戶腋粥,用戶信息需要延遲加載 -->
<select id="findOrdersUserLazy" resultMap="OrdersUserLazyResultMap">
SELECT * FROM orders
</select>
說明:從上面的注釋中我們可以明確的知道首先我們是查詢訂單信息(單表),在resultMap
中我們使用association
的延遲加載功能延遲加載用戶信息闹瞧,而用戶信息的查詢我們可以使用之前配置過的查詢statement
奥邮。
注意:在配置延遲加載的時候我們使用了之前的查詢select="cn.itcast.mapper.UserMapper.findUserById"
,由于不再同一個mapper.xml
中脚粟,所以要加上命名空間:
UserMapper.xml
<!-- 查詢蘸朋,通過用戶id進(jìn)行查詢-->
<select id="findUserById" parameterType="java.lang.Integer" resultType="User">
SELECT * FROM USER WHERE id = #{value}
</select>
2.2 配置延遲加載功能
延遲加載配置藕坯,默認(rèn)是沒有開啟延遲加載的,需要在全局配置文件SqlMapConfig.xml
的settings
中進(jìn)行配置吐根。
設(shè)置項 | 描述 | 允許值 | 默認(rèn)值 |
---|---|---|---|
lazyLoadingEnabled |
全局性設(shè)置懶加載佑惠。如果設(shè)置為"false" 齐疙,則所有相關(guān)聯(lián)的都會被初始化加載 |
true/false |
false |
aggressiveLazyLoading |
當(dāng)設(shè)置為"true" 的時候,懶加載的對象可能被任何懶屬性全部加載赌厅。否咋轿塔,每個屬性都按需加載勾缭。 |
true/false |
true |
配置:
<settings>
<!-- 打開延遲加載的開關(guān),再將積極加載改為消極加載(即按需加載) -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
2.3 mapper.java
OrdersMapper.java
//查詢訂單毒嫡,關(guān)聯(lián)查詢用戶兜畸,其中用戶信息是延遲加載
public List<Orders> findOrdersUserLazy() throws Exception;
2.4 測試
OrdersMapperTest.java
//查詢訂單關(guān)聯(lián)查詢用戶信息,其中用戶信息使用延遲加載
@Test
public void testFindOrdersUserLazy() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//創(chuàng)建代理對象
OrdersMapper orders = sqlSession.getMapper(OrdersMapper.class);
//查詢訂單信息(單表)
List<Orders> list = orders.findOrdersUserLazy();
//遍歷上面的訂單列表
for(Orders order : list){
User user = order.getUser();//這里實現(xiàn)按需加載
System.out.println(user);
}
System.out.println(list.size());
sqlSession.close();
}
說明:
- 1.執(zhí)行上面的
mapper
接口中的方法伐蒂,內(nèi)部調(diào)用findOrdersUserLazy
逸邦,只查詢orders
信息(單表) - 2.在程序中去遍歷
List<Orders>
龄坪,當(dāng)我們調(diào)用Orders
中的getUser
方法時,就開始進(jìn)行延遲加載烛卧。 - 3.延遲加載去調(diào)用
findUserById
這個方法獲取用戶信息总放。 - 測試結(jié)果為:
可以看到當(dāng)用戶id
一樣時局雄,是不會重復(fù)發(fā)送sql
語句的存炮,這就是后面要將的緩存的概念。
2.5 如果我們不使用mybatis提供的延遲加載宫盔,我們?nèi)绾螌崿F(xiàn)延遲加載享完?
- 實現(xiàn)方法如下:
定義兩個mapper
方法- 查詢訂單列表
- 根據(jù)用戶
id
查詢用戶信息
- 根據(jù)用戶
- 實現(xiàn)思路:
先查詢第一個mapper
的方法得到訂單信息列表般又,在程序中(service
類中),按需去調(diào)用第二個mapper
方法去查詢用戶信息寄悯。當(dāng)然這也是mybatis
實現(xiàn)延遲加載的原理堕义。
總結(jié):使用延遲加載方法,先去查詢簡單的sql
(最好是單表,也可以是關(guān)聯(lián)查詢)糖耸,然后再去按需加載關(guān)聯(lián)查詢的其他信息嘉竟。最后對于collection
實現(xiàn)延遲加載的方式和上面是一樣的,這里不再細(xì)說舍扰。